如果我调用WCF服务方法,我会做这样的事情:
proxy.DoSomethingAsync();
proxy.DoSomethingAsyncCompleted += OnDoSomethingAsyncCompleted;
我怎样才能使用新的async
ctp做同样的事情?
我想我需要proxy.DoSomethingTaskAsync
或proxy.DoSomethingAsync().ToTask()
之类的东西? Web服务调用需要返回Task<T>
才能使用await
关键字,但是如何?
答案 0 :(得分:10)
在CTP中,有一些工厂方法可以将常规APM功能(开始/结束)转换为与新的async关键字兼容的功能,例如:
Stream s = new FileStream("C:\test.txt", FileMode.CreateNew);
byte []buffer = new byte[100];
int numBytesRead = await Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
所以在你的情况下,你可以做相同的事情,然后你就这样称呼它:
async proxy.DoSomethingTaskAsync()
有关详细信息,请参阅CTP讨论组的this thread
答案 1 :(得分:6)
使用async-await的异步服务非常敏感,因为它可以交错许多客户端调用并并行执行它们(2)。 尽管如此,该服务可以在一个线程(3)上完全运行线程安全,并且可以是单例服务(1)或由框架为会话或仅调用创建的服务对象。
实施服务时,请注意ServiceBehaviourAttributes(1)...(3):
[ServiceContract( Namespace="X", Name="TheContract" )]
public interface IAsyncContractForClientAndService
{
[OperationContract]
Task<TResponse> 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<TResponse> 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,您无需关心锁。原子的,不可中断的代码段大致从一个等待到下一个。 注意共享服务数据在每次等待时都处于一致状态,并注意来自一个客户端的连续请求可能不按其发送顺序进行响应。
在客户端,异步服务操作是可以接受的:
var response = await client.Channel.SendReceiveAsync( request );
在操作合同中无法使用 out 或 ref 参数。所有响应数据必须由返回值Task(T)传递 我在AsyncWcfLib中使用此界面,它支持Actor based programming model。
答案 2 :(得分:4)
Async CTP中有一个WCF示例,它将向您展示如何在WCF中使用async / await模型。
就在WCF中支持此模型的计划而言,您可以查看以下帖子:
希望这有帮助。
阿马德奥
答案 3 :(得分:2)
如Matt所述,有一种TaskFactory.FromAsync
方法可让您从Task
/ Begin
对中创建End
。您需要在添加WCF引用时启用异步端点,然后可以使用扩展方法自行封装它们。
正如Amadeo所提到的,在(C# WCF) Stock Quotes
目录下的Async CTP中有一个示例。
同样在该目录中,有一个TaskWsdlImportExtension
项目。添加对该dll的引用并修改.config:
<configuration>
<system.serviceModel>
<client>
<metadata>
<wsdlImporters>
<extension type="TaskWsdlImportExtension.TaskAsyncWsdlImportExtension, TaskWsdlImportExtension" />
</wsdlImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
然后你根本不需要做自己的包装; TaskWsdlImportExtension
将为您完成。
答案 4 :(得分:2)
让异步客户端调用同步服务是很常见的 以下客户和服务合同匹配(在幕后使用了一点魔力):
[ServiceContract( Namespace="X", Name="TheContract" )]
public interface IClientContractAsynchronous
{
[OperationContract]
Task<TResponse> 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 based programming model。
答案 5 :(得分:1)