为手动生成的WCF(客户端)代理实现异步/等待模式

时间:2016-03-29 07:53:47

标签: c# .net wcf asynchronous async-await

鉴于此界面

 //read xml file
 if(...your logic here...)
    btn.Visibitity= System.Windows.Visibility.Visible;

我想手动(即,不使用VS中的scvutil或Add Service Reference)创建客户端代理。

我是按照以下方式做的

[ServiceContract]
public interface IProductService
{
    [OperationContract]
    Product Get(int id);
}

我的问题我还想要这种方法的async / await版本,只在客户端,服务器端仍然是同步的。

我希望这是一个通用解决方案,因为我有很多这种方法和服务。

2 个答案:

答案 0 :(得分:9)

如果您正在使用ChannelFactory来允许async-await,那么您的界面需要返回TaskTask<T>

它会强制您的服务器端同时返回一个任务,但是如果您坚持要保持同步,那么您可以与Task.CompletedTaskTask.FromResult同步执行此操作(但如果您有选项,为什么会这样做)

例如:

[ServiceContract]
interface IProductService
{
    [OperationContract]
    Task<Product> GetAsync(int id);
}

class ProductService : IProductService
{
    ChannelFactory<IProductService> factory;

    public ProductService()
    {
        factory = new ChannelFactory<IProductService>("*");
    }

    public Task<Product> GetAsync(int id)
    {
        var channel = factory.CreateChannel();
        return channel.GetAsync(id);
    }
}

class ProductAPI : IProductService
{
    public Task<Product> GetAsync(int id) => Task.FromResult(Get(id))
}

答案 1 :(得分:2)

实际上,您可以在不更改服务本身的情况下执行此操作。您只需定义第二个接口,其中包含方法的异步和[ServiceContract(Name = "NameOfTheIterfaceWhichIsActuallyExposedOnTheServer")]返回版本,并标有GetAsync()

在您提到的示例中,您将使用[ServiceContract(Name = "IProductService")] public interface IProductServiceAsync { [OperationContract] Task<Product> GetAsync(int id); } 操作定义第二个接口:

IProductService

即使您的服务仍在实施并公开ChannelFactory<IProductServiceAsync>,您也可以使用GetFoo来调用它。只要方法名称与GetFooAsync / Optional模式匹配,所有内容都将正常工作。这就是Visual Studio中添加服务引用的方式可以为您生成同步服务的异步服务引用。

有关此工作的详细说明,请参阅Calling a synchronous WCF method asynchronously using ChannelFactory