2010-11-04 115 views
15

如果我調用WCF服務方法,我會做這樣的事情:異步CTP - 我如何使用異步/等待對該調用WCF服務?

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

怎麼能使用新async CTP我一樣嗎? 我想我會需要這樣的東西proxy.DoSomethingTaskAsyncproxy.DoSomethingAsync().ToTask()? Web服務調用需要返回Task<T>能夠使用await關鍵詞,但如何?

+0

Corr。 +1只是爲了向我介紹一些有光澤和新的東西。 – spender 2010-11-04 09:56:06

回答

10

在CTP有工廠方法做轉向常規APM功能(開始/結束)到那些與新的異步關鍵字兼容的工作,例如:

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() 

this thread在CTP討論組更多信息

+0

謝謝你的回答,但我仍然不明白。我知道這是如何工作的流讀取,如您在示例中所示,但我該如何將此應用於wcf服務調用? – Roger 2010-11-04 11:22:36

+0

生成的代理將具有BeginDoSomething/EndDoSomething方法(只要您向svcutil /嚮導傳遞正確的選項)。 – Brian 2010-11-04 12:55:04

2

正如馬特提到的,有一種方法TaskFactory.FromAsync,允許你從Begin/End對創建Task。您需要在添加WCF引用時啓用異步端點,然後使用擴展方法自行將它們包裝起來。

正如阿馬德奧所提到的,存在的這在異步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會爲你做。

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); 
    } 

客戶端界面直接awaitable:

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

這是不可能使用ref運營合同中的參數。所有的響應數據都必須在返回值中傳遞。這對我來說實際上是一個突破性的改變。
我在AsyncWcfLib使用這個接口,它支持Actor based programming model

+0

你應該把你的答案合併爲1嗎? – 2013-07-28 03:20:31

6

使用異步等待的異步服務非常靈敏,因爲它可以交織許多客戶端調用並且並行執行它們(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絕!在您打開()ServiceHost的那一刻出現。 使用SynchronizationContext,你不需要關心鎖。原子,不可中斷的代碼段大致從一個到另一個延伸。 請注意,共享服務數據在每次等待時處於一致狀態,並且要注意來自一個客戶端的連續請求可能不會按照它們發送的順序進行響應。

在客戶端,異步服務操作awaitable:

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

不可能在操作合同使用REF參數。所有響應數據必須通過返回的值Task(T)傳遞。
我在AsyncWcfLib中使用這個接口,它支持Actor based programming model

1

您正確地指出,異步/等待是圍繞返回任務和任務的方法構建的(有關異步/等待的工作的詳細說明,請參閱here)。以下是如何生成的WCF服務基於任務的方法:

  1. 的Visual Studio 2012 RC在「配置服務引用」對話框中的附加複選框:「基於任務操作」。雖然我沒有看到MSDN中記錄的選項,但我期望它專門存在允許在WCF調用中實現無縫異步/等待。

  2. 對於早期版本,請看this post,描述一個擴展,它允許即使使用CTP也可以在WCF上生成任務<>的基於方法。