异步CTP – 如何使用async / await来调用wcf服务?

如果我调用WCF服务方法,我会这样做:

proxy.DoSomethingAsync(); proxy.DoSomethingAsyncCompleted += OnDoSomethingAsyncCompleted; 

我怎么能使用新的async ctp做同样的事情? 我想我需要像proxy.DoSomethingTaskAsyncproxy.DoSomethingAsync().ToTask() ? Web服务调用需要返回一个Task才能使用await关键字,但是如何?

在CTP中,有工厂方法可以将常规APMfunction(开始/结束)转换为与新的async关键字兼容的工作方法,例如:

 Stream s = new FileStream("C:\test.txt", FileMode.CreateNew); byte []buffer = new byte[100]; int numBytesRead = await Task.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null); 

所以在你的情况下,你可以做相同的,然后你会这样称呼它:

 async proxy.DoSomethingTaskAsync() 

有关详细信息,请参阅CTP讨论组中的此主题

使用async-await的异步服务非常敏感,因为它可以交错许多客户端调用并并行执行它们(2)。 尽管如此,该服务可以在一个线程(3)上完全运行线程安全,并且可以是单例服务(1)或由框架为会话或仅调用创建的服务对象。

在实施服务时,请注意ServiceBehaviourAttributes(1)…(3):

  [ServiceContract( Namespace="X", Name="TheContract" )] public interface IAsyncContractForClientAndService { [OperationContract] Task SendReceiveAsync( TRequest req ); } [ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, // (1) // also works with InstanceContextMode.PerSession or PerCall ConcurrencyMode = ConcurrencyMode.Multiple, // (2) UseSynchronizationContext = true)] // (3) public MyService : IAsyncContractForClientAndService { public async Task SendReceiveAsync( TRequest req ) { DoSomethingSynchronous(); await SomethingAsynchronous(); // await lets other clients call the service here or at any await in // subfunctions. Calls from clients execute 'interleaved'. return new TResponse( ... ); } } 

要在一个线程上运行每个调用,在Open()ServiceHost时必须存在System.Threading.SynchronizationContext.Current!= null。 使用SynchronizationContext,您无需关心锁。 primefaces的,不可中断的代码段大致从一个等待到下一个。 注意共享服务数据在每次等待时都处于一致状态,并注意来自一个客户端的连续请求可能不按其发送顺序进行响应。

在客户端,异步服务操作是等待的:

  var response = await client.Channel.SendReceiveAsync( request ); 

在操作合同中不可能使用outref参数。 所有响应数据必须由返回值Task(T)传递。
我在AsyncWcfLib中使用这个接口,它支持基于Actor的编程模型 。

Async CTP中有一个WCF示例,它将向您展示如何在WCF中使用async / await模型。

关于在WCF中支持此模型的计划,您可以查看以下post:

http://blogs.msdn.com/b/endpoint/archive/2010/11/13/simplified-asynchronous-programming-model-in-wcf-with-async-await.aspx

希望这可以帮助。

阿马德奥

正如Matt所提到的,有一个TaskFactory.FromAsync方法,允许您从Begin / End对创建Task 。 您需要在添加WCF引用时启用异步端点,然后您可以使用扩展方法自行封装它们。

正如Amadeo所提到的,在(C# WCF) Stock Quotes目录下的Async CTP中有一个这样的示例。

同样在该目录中,有一个TaskWsdlImportExtension项目。 添加对该DLL的引用并修改.config:

            

然后你根本不需要做自己的包装; TaskWsdlImportExtension将为您完成。

让异步客户端调用同步服务是很常见的。
以下客户和服务合同匹配(幕后使用的有点魔术):

  [ServiceContract( Namespace="X", Name="TheContract" )] public interface IClientContractAsynchronous { [OperationContract] Task SendReceiveAsync( TRequest req ); } [ServiceContract( Namespace="X", Name="TheContract" )] public interface IServiceContractSynchronous { [OperationContract] TResponse SendReceive( TRequest req ); } 

客户端界面是直接等待的:

  var response = await client.Channel.SendReceiveAsync( request ); 

在operaton合同中不可能使用outref参数。 必须在返回值中传递所有响应数据。 这对我来说实际上是一个突破性的变化。
我在AsyncWcfLib中使用这个接口,它支持基于Actor的编程模型 。

你正确地指出async / await是围绕返回Task和Task的方法构建的(有关async / await工作的一个很好的解释,请参见此处 )。 以下是如何为WCF服务生成基于任务的方法:

  1. Visual Studio 2012 RC在“配置服务引用”对话框中有一个附加复选框:“生成基于任务的操作”。 虽然我没有在MSDN中看到该选项,但我希望它能够专门用于在WCF调用上实现无缝的异步/等待。

  2. 对于早期版本,请看一下这篇文章 ,描述一个扩展,它允许在WCF上生成基于Task <>的方法,即使使用CTP也是如此。