不能在同一个合同中有两个同名的操作(异步和非)

Cannot have two operations in the same contract with the same name (Async & Non)

激活以下服务时出现以下异常(同一合同中不能有两个具有相同名称的操作,方法 ExecuteAsync 和 Execute)。

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        byte[] Execute(MyRequest request);

        [OperationContract]
        Task<byte[]> ExecuteAsync(MyRequest request);
    }

如果您使用 svcutil.exe 创建服务引用,我想这很有意义,因为基于任务的操作是自动为您创建的。但是,我不想添加服务引用,而只是使用标准的 ChannelFactory 来创建 WCF 通道。如果不将异步方法重命名为其他方法,是否还有其他方法可以做到这一点?或者我必须将客户端上的同步方法包装在 Task.Run?

以上内容无效,因为 WCF 本身为您的每个 OperationContract 创建了两种方法 Execute() 一种是同步方法,另一种是异步方法,可以通过编写 ServiceClientObj.ExexuteAsync(request) 在客户端调用,所以您不需要在 IMyService 中显式添加异步方法。框架本身负责生成每个 Operation

async 方法

异步方法是一种 .NET 结构。 Web 服务标准不知道它们。 You do not need to do anything to enable clients to use async operations because server and client are independent. 为客户端和服务器独立选择同步或异步。

由于这个事实常常令人难以置信,所以让我声明以下内容:您可以拥有一个带有异步客户端的同步服务器,反之亦然。

您可以声明其中一个,但不能同时声明两个。 WCF 将自动使任一方法在生成的通道代理中工作——您可以将使用异步方法的接口连接到使用同步方法的实现,反之亦然。

如果你想在客户端和服务器代码之间共享接口定义(这不是不合理的)并且不得不接受一个,你最好的选择是异步的:只提供同步意味着异步客户端必须浪费一个线程,仅提供异步意味着调用者可以选择在必要时自己阻塞和浪费线程。由于调用 WCF 服务涉及 I/O,您肯定希望为客户端提供异步选项,即使服务器具有同步实现。

这是我所做的。我有两个单独的合同。一个用于客户端,一个用于服务器:

namespace ServiceLibrary.Server
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        byte[] Execute(MyRequest request);
    }
}

namespace ServiceLibrary.Client
{
    [ServiceContract]
    public interface IMyService : Server.IMyService
    {
        [OperationContract]
        Task<byte[]> ExecuteAsync(MyRequest request);
    }
}

因为两个 ServiceContracts 共享相同的名称,所以 OperationContracts 的 Action 和 ReplyAction 对于 async 和 sync 方法是相同的。客户端现在同时具有同步和异步版本,服务器保持不变。

尝试在OperationMethod中添加名称,使其更简单。

[ServiceContract]
public interface IMyService
{
    [OperationContract(Name = "Service1")]
    byte[] Execute(MyRequest request);

    [OperationContract(Name = "Service2")]
    Task<byte[]> ExecuteAsync(MyRequest request);
}

我知道这是迟到的答案,但总有人在寻找更简单的方法。

考虑您有两个方法,名称分别为 SearchSaleMansAllSearchSaleMans。但是您想在同一地址显示它们。我是这样做的:

[ServiceContract]
public interface IUserService
{
    [OperationContract]
    List<UserSalemanModel> SearchSaleMansAll();
    
    [OperationContract]
    List<UserSalemanModel> SearchSaleMans(string data);
}

    
    public class UserService : IUserService
    {
        [WebInvoke(
            Method = "GET",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "SearchSaleMans")]
        public List<UserSalemanModel> SearchSaleMansAll()
        {
            var saleMane = new UserDL().SearchSaleMans("");
            return saleMane;
        }


        [WebInvoke(
            Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "SearchSaleMans/{data}")]
        public List<UserSalemanModel> SearchSaleMans(string data)
        {
            var saleMane = new UserDL().SearchSaleMans(data);
            return saleMane;
        }
}

您可以使用 WebGet 而不是 WebInvoke(Method = "GET", ...。 重点是UriTemplate。请根据您的需要自定义此部分。