WCF / svcutil in .NET 4.5 generates unusable code

2019-04-26 14:56发布

问题:

With .NET 4.5, my WCF creation using svcutil suddenly seems to break (I've been using only .NET 4.0 until very recently) ....

With the default settings I'm using to convert a pre-existing WSDL to my C# WCF proxy class:

c:> svcutil.exe /n:*,MyNamespace /out:WebService MyService.wsdl

I get this C# file created:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="MyService.IMyService1")]
public interface IMyService1
{
    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService1/IsAlive", ReplyAction="http://tempuri.org/IMyService1/IsAliveResponse")]
    [System.ServiceModel.FaultContractAttribute(typeof(MyService.MyFault), Action="http://tempuri.org/IMyService1/IsAliveErrorInfoFault", Name="MyServiceErrorInfo", Namespace="http://schemas.datacontract.org/2004/07/MyService.Types")]
    string IsAlive();

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService1/IsAlive", ReplyAction="http://tempuri.org/IMyService1/IsAliveResponse")]
    System.Threading.Tasks.Task<string> IsAliveAsync();

This doesn't work - if I try to instantiate an implemention of this interface in a ServiceHost

using (ServiceHost svcHost = new ServiceHost(typeof(MyService01Impl)))
{
    svcHost.Open();
    Console.WriteLine("Host running ...");

    Console.ReadLine();
    svcHost.Close();
}

I get this error:

Cannot have two operations in the same contract with the same name, methods 'IsAlive' and 'IsAliveAsync' in type 'MyService01Impl' violate this rule. You can change the name of one of the operations by changing the method name or by using the Name property of OperationContractAttribute.

Why does svcutil suddenly generate code that doesn't work??

If I use the /async keyword with svcutil, then I get the "old-style" async pattern with BeginIsAlive and EndIsAlive and things work again - but how can I tell WCF / svcutil to generate no async stuff at all?

回答1:

svcutil by default generates a proxy class with both synchronous and Task-based methods, eg:

public interface IService1
{
    ...
    string GetData(int value);
    ...    
    System.Threading.Tasks.Task<string> GetDataAsync(int value);
    ...
}

To generate a proxy with only synchronous methods, you need to use /syncOnly. This will omit the Task-based version:

public interface IService1
{
   ...
   string GetData(int value);
   ...
}

In both cases, the proxy class itself inherits from ClientBase:

public partial class Service1Client : System.ServiceModel.ClientBase<IService1>, IService1

Finally, the /serviceContract switch generates only the interface and DTOs necessary for generating a dummy service