Skip to content

ServiceContractAttribute.ConfigurationName differs from what Visual Studio generated #5359

Open
@KalleOlaviNiemitalo

Description

@KalleOlaviNiemitalo

Describe the bug

When Visual Studio 2017 generates code for a Service Reference, it sets ServiceContractAttribute.ConfigurationName = the name of the Service Reference + "." + the name of the interface type. However, dotnet-svcutil 2.1.0 instead sets ServiceContractAttribute.ConfigurationName = the full name of the interface type. This difference makes the generated code incompatible with existing configuration files, hindering our migration from .NET Framework to .NET.

(We're first switching to SDK-style csproj files and dotnet-svcutil before we start multitargeting.)

To Reproduce

The attached ConfigurationNameDemo.zip demonstrates the problem. It contains three projects:

  • DemoService is a WCF web service. It has an old-style C# project file and targets .NET Framework 4.8.

  • DemoProjectVS is a console application that uses DemoService via a "Connected Service" (WCFMetadata item) in Visual Studio. It has an old-style C# project file and targets .NET Framework 4.8.

    Visual Studio generates ConfigurationName="DemoService.IService1":

    namespace DemoProjectVS.DemoService {
    
    
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
        [System.ServiceModel.ServiceContractAttribute(ConfigurationName="DemoService.IService1")]
        public interface IService1 {

    The App.config file then has: contract="DemoService.IService1":

          <endpoint address="http://localhost:59055/Service1.svc" binding="basicHttpBinding"
              bindingConfiguration="BasicHttpBinding_IService1" contract="DemoService.IService1"
              name="BasicHttpBinding_IService1" />
  • DemoProjectSvcUtil is a console application that uses DemoService via code generated by dotnet-svcutil 2.1.0, augmented with a partial class that lets the application use the ClientBase<TChannel>(string endpointConfigurationName) constructor. It has an SDK-style C# project file and targets .NET Framework 4.8.

    dotnet-svcutil generates ConfigurationName="DemoProjectSvcUtil.DemoService.IService1":

    namespace DemoProjectSvcUtil.DemoService
    {
        
        
        [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
        [System.ServiceModel.ServiceContractAttribute(ConfigurationName="DemoProjectSvcUtil.DemoService.IService1")]
        internal interface IService1
        {

    The App.config file then has: contract="DemoProjectSvcUtil.DemoService.IService1":

          <endpoint address="http://localhost:59055/Service1.svc" binding="basicHttpBinding"
              bindingConfiguration="BasicHttpBinding_IService1" contract="DemoProjectSvcUtil.DemoService.IService1"
              name="BasicHttpBinding_IService1" />

Expected behavior

Have some way to generate the same ServiceContractAttribute.ConfigurationName as in Service Reference in Visual Studio. For example, the parameters JSON file could support a "configurationNamespaceMappings" akin to "namespaceMappings":

{
  "providerId": "Microsoft.Tools.ServiceModel.Svcutil",
  "version": "2.1.0",
  "options": {
    "configurationNamespaceMappings": [
      "*, DemoService"
    ]
    "inputs": [
      "Service1.wsdl",
      "Service11.xsd",
      "Service12.xsd"
    ],
    "internal": true,
    "namespaceMappings": [
      "*, DemoProjectSvcUtil.DemoService"
    ],
    "outputFile": "Reference.cs",
    "sync": true,
    "targetFramework": "net48",
    "typeReuseMode": "All"
  }
}

Alternatively, the parameters JSON file could support a mapping from Type.FullName to the desired ServiceContractAttribute.ConfigurationName. This would be more tedious to configure if there are multiple services in the same WSDL:

    "configurationNameMappings": [
      "DemoProjectSvcUtil.DemoService.IService1, DemoService.IService1"
    ]

Either way, the parameters would then cause the generated code to change:

--- a/DemoProjectSvcUtil/ServiceReferences/DemoService/Reference.cs
+++ b/DemoProjectSvcUtil/ServiceReferences/DemoService/Reference.cs
@@ -10,11 +10,11 @@
 namespace DemoProjectSvcUtil.DemoService
 {


     [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
-    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="DemoProjectSvcUtil.DemoService.IService1")]
+    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="DemoService.IService1")]
     internal interface IService1
     {

         [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService1/GetData", ReplyAction="http://tempuri.org/IService1/GetDataResponse")]
         string GetData();

Screenshots

None.

Additional context

It seems Visual Studio uses VSWCFServiceContractGenerator.PatchConfigurationName to change ConfigurationName after ServiceContractGenerator has generated it. The VSWCFServiceContractGenerator class does not exist in https://github.com/dotnet/wcf/.

Metadata

Metadata

Assignees

Labels

toolingAn issues related to any tool shipped from this repo.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions