`dotnet-svcutil` generates incomplete client classes when providing multiple WSDL services
jacobjmarks opened this issue · 2 comments
Describe the bug
When attempting to generate a single C# service client reference for more than one WSDL spec - for the purposes of type reuse - all but the last service client class contains missing elements. See details below.
To Reproduce
Please find below a sample project which demonstrates this issue.
https://github.com/jacobjmarks/dotnet-svcutil-issue-demo
Contained within the repository are 3 WSDL services which closely represent the format of services I am looking to generate.
In general, all services each contain a single operation with unique request/response models, and all services reference a common reference type called ServiceFault
, in this case. I am trying to generate the service clients in a way such that these common reference types between services are in fact shared in the resultant C# code.
There are two scripts as described below:
-
generate-service-clients.ps1
Uses thedotnet-svcutil
command once for each service; i.e.dotnet-svcutil service-a.wsdl dotnet-svcutil service-b.wsdl dotnet-svcutil service-c.wsdl
Generates separate service clients within the
MyProject/ServiceReference
folder; i.e.ServiceA.cs
,ServiceB.cs
,ServiceC.cs
.
The results here are as expected: All service client classes contain the following constructors, as well as thepartial ConfigureEndpoint
method, as below;static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials); public ServiceAServiceClient() : base(ServiceAServiceClient.GetDefaultBinding(), ServiceAServiceClient.GetDefaultEndpointAddress()) { ... } public ServiceAServiceClient(EndpointConfiguration endpointConfiguration) : base(ServiceAServiceClient.GetBindingForEndpoint(endpointConfiguration), ServiceAServiceClient.GetEndpointAddress(endpointConfiguration)) { ... } public ServiceAServiceClient(EndpointConfiguration endpointConfiguration, string remoteAddress) : base(ServiceAServiceClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress)) { ... } public ServiceAServiceClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) : base(ServiceAServiceClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress) { ... } public ServiceAServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { ... }
-
generate-shared-service-clients.ps1
Uses thedotnet-svcutil
once for all services; i.e.dotnet-svcutil service-a.wsdl service-b.wsdl service-c.wsdl
Generates a shared service client within the
MyProject/SharedServiceReference
folder; i.e.Services.cs
.
The results here are not as expected: All but the last service client class contains only the following constructor (thepartial ConfigureEndpoint
method is also missing):public ServiceAServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { ... }
In addition, the last (fully-featured) service client class seems to erroneously contain the
GetBindingForEndpoint
andGetEndpointAddress
methods as well as theEndpointConfiguration
enum which contain endpoint information for all three services.
Expected behavior
When passing multiple WSDL services to the dotnet-svcutil
command, fully-featured service client classes are generated as if they were individually generated, and share reference types where applicable.
The GetBindingForEndpoint()
, GetEndpointAddress()
, and enum EndpointConfiguration
elements are abstracted in a way such that etiher
- All services reference a shared implementation which contains information for all services
- OR All services reference a local implementation which contains information only for that single service
Additional context
Project is targeting net6.0
Generated with dotnet-svcutil/2.1.0
Notes
Please do let me know if this is not in fact an intended use case for this tool, or I am approaching this the wrong way.
@jacobjmarks, thanks for raising the issue.
By debugging the tool, I found each endpoint to be generated code for comes from a WsdlEndpointConversionContext instance, this context is created from a binding instance which is returned from wsdlDocument.GetBinding(XmlQulifiedName name) and the name parameter here is the same for all the three wsdl documents, this results in the code always returned the same binding instance, in this specific case, that instance's ServiceDescription property happens to be the last one of the imported service description collection named ServiceCService. I think this leads to messy code being generated in the end as described in issue.
It behaves similarly for Svcutil.exe which is the .NET Framework version of the tool.
You can update the wsdl files so that the three wsdl binding names are different from each other and then rerun the tool command. For example, update service-a.wsdl as follows, and do similar modifications to service-b.wsdl and service-c.wsdl. Hope this workaround unblocks you.
Closing as no response, feel free to reopen if this is still an issue for you.