异步CTP – 如何使用async / await来调用wcf服务?
如果我调用WCF服务方法,我会这样做:
proxy.DoSomethingAsync(); proxy.DoSomethingAsyncCompleted += OnDoSomethingAsyncCompleted;
我怎么能使用新的async
ctp做同样的事情? 我想我需要像proxy.DoSomethingTaskAsync
或proxy.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 );
在操作合同中不可能使用out或ref参数。 所有响应数据必须由返回值Task(T)传递。
我在AsyncWcfLib中使用这个接口,它支持基于Actor的编程模型 。
Async CTP中有一个WCF示例,它将向您展示如何在WCF中使用async / await模型。
关于在WCF中支持此模型的计划,您可以查看以下post:
希望这可以帮助。
阿马德奥
正如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合同中不可能使用out或ref参数。 必须在返回值中传递所有响应数据。 这对我来说实际上是一个突破性的变化。
我在AsyncWcfLib中使用这个接口,它支持基于Actor的编程模型 。
你正确地指出async / await是围绕返回Task和Task的方法构建的(有关async / await工作的一个很好的解释,请参见此处 )。 以下是如何为WCF服务生成基于任务的方法:
-
Visual Studio 2012 RC在“配置服务引用”对话框中有一个附加复选框:“生成基于任务的操作”。 虽然我没有在MSDN中看到该选项,但我希望它能够专门用于在WCF调用上实现无缝的异步/等待。
-
对于早期版本,请看一下这篇文章 ,描述一个扩展,它允许在WCF上生成基于Task <>的方法,即使使用CTP也是如此。