使用 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( ... );
}
}
要在一个线程上运行每个调用,System.Threading.SynchronizationContext.Current != null 在您 Open() ServiceHost 时必须存在。使用 SynchronizationContext,您无需关心锁。原子的、不可中断的代码段大致从一个 await 延伸到下一个。请注意共享服务数据在每次等待时都处于一致状态,并注意来自一个客户端的连续请求可能不会按照它们发送的顺序进行响应。
在客户端,异步服务操作是等待的:
var response = await client.Channel.SendReceiveAsync( request );
操作合约中不能使用out或ref参数。所有响应数据都必须通过返回值 Task(T) 传递。我在AsyncWcfLib
中使用这个接口,它支持基于Actor 的编程模型。