16

如果我调用 WCF 服务方法,我会执行以下操作:

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

我怎么能用新的asyncctp 做同样的事情?我想我需要类似proxy.DoSomethingTaskAsyncor的东西proxy.DoSomethingAsync().ToTask()?Web服务调用需要返回aTask<T>才能使用await关键字,但是如何?

4

6 回答 6

10

在 CTP 中,有一些工厂方法可以将常规 APM 函数(Begin/End)转换为与新的 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 讨论组上的此线程

于 2010-11-04T10:31:06.397 回答
7

使用 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 );

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

于 2012-04-04T22:17:49.907 回答
4

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

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

关联

希望这可以帮助。

阿马德奥

于 2010-11-13T15:31:40.403 回答
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 );

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

于 2012-03-22T19:44:06.140 回答
2

正如马特所提到的,有一种TaskFactory.FromAsync方法可以让您TaskBegin/End对创建一个。您需要在添加 WCF 引用时启用异步终结点,然后您可以使用扩展方法自行包装它们。

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

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

<configuration>
 <system.serviceModel>
  <client>
   <metadata>
    <wsdlImporters>
     <extension type="TaskWsdlImportExtension.TaskAsyncWsdlImportExtension, TaskWsdlImportExtension" />
    </wsdlImporters>
   </metadata>
  </client>
 </system.serviceModel>
</configuration>

然后你根本不需要自己包装;TaskWsdlImportExtension会为你做的。

于 2011-08-30T14:17:03.320 回答
1

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

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

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

于 2012-08-09T00:00:02.530 回答