2010-11-04 8 views
15

Wenn ich einen WCF-Dienst-Methode aufrufen, würde ich so etwas tun:Async CTP - Wie kann ich async/await verwenden, um einen WCF-Dienst anzurufen?

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

Wie ich das gleiche tun könnte das neue async CtP mit? Ich denke, ich würde etwas wie proxy.DoSomethingTaskAsync oder proxy.DoSomethingAsync().ToTask() brauchen? Der Webservice-Aufruf muss Task<T> zurückgeben, um das Schlüsselwort await verwenden zu können, aber wie ??

+0

Corr. +1 einfach, um mich etwas Glänzendes und Neues vorzustellen. – spender

Antwort

10

Im CTP gibt es Factory-Methoden, die die Arbeit des Drehens regelmäßigen APM Funktionen tun (Beginn/Ende) in diejenigen, die mit dem neuen Asynchron-Schlüsselwort kompatibel sind, zum Beispiel:

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

Also in Ihrem Fall Sie können das Äquivalent tun und dann würden Sie es dann rufen Sie wie folgt:

async proxy.DoSomethingTaskAsync() 

this thread auf der CTP-Diskussionsgruppe für weitere Informationen

+0

Danke für die Antwort, aber ich verstehe es immer noch nicht. Ich verstehe, wie dies für Stream-lesen funktioniert, wie Sie in Ihrem Beispiel zeigen, aber wie kann ich dies auf einen Aufruf von WCF-Service anwenden? – Roger

+0

Der generierte Proxy wird BeginDoSomething/EndDoSomething-Methoden haben (vorausgesetzt, Sie übergeben die richtigen Optionen an svcutil/wizards). – Brian

2

Wie von Matt erwähnt, gibt es eine TaskFactory.FromAsync Methode, die Sie eine Task von einem Begin/End Paar erstellen können. Sie müssen asynchrone Endpunkte aktivieren, wenn Sie Ihre WCF-Referenz hinzufügen, und Sie können sie dann mithilfe von Erweiterungsmethoden selbst einpacken.

Wie von Amadeo erwähnt, gibt es ein Beispiel davon im Async CTP unter dem Verzeichnis (C# WCF) Stock Quotes.

Auch in diesem Verzeichnis befindet sich ein Projekt TaskWsdlImportExtension. Fügen Sie einen Verweis auf diese DLL und ändern Sie Ihre .config als solche:

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

Dann müssen Sie gar nicht tun, um Ihre eigene Verpackung; Die TaskWsdlImportExtension wird es für Sie tun.

2

Es ist durchaus üblich, dass asynchrone Clients einen synchronen Dienst aufrufen.
Die folgende Client und Serviceverträge Spiel (ein bisschen Magie hinter den Kulissen verwendet):

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

Die Client-Schnittstelle ist direkt awaitable:

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

Es ist nicht möglich aus zu verwenden oder ref Parameter im Betriebsvertrag. Alle Antwortdaten müssen im Rückgabewert übergeben werden. Das war eine echte Veränderung für mich.
Ich benutze diese Schnittstelle in AsyncWcfLib, unterstützt eine Actor based programming model.

+0

Sollten Sie 2 Ihre Antworten in 1 zusammenführen? –

6

Ein Async-Dienst, der async-await verwendet, reagiert sehr schnell, da er viele Client-Aufrufe verschachteln und parallel ausführen kann (2). Trotzdem kann der Dienst vollständig threadsicher auf einem Thread (3) ausgeführt werden und kann ein Singleton-Dienst (1) oder ein Dienstobjekt sein, das von dem Framework für eine Sitzung oder einen Aufruf nur erstellt wird.

, wenn der Dienst der Umsetzung beachten Sie bitte die 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(...); 
     } 
    } 

Um jeden Anruf auf einem Thread laufen, ein System.Threading.SynchronizationContext.Current = null muss! vorhanden sein, wenn Sie den ServiceHost öffnen(). Mit dem SynchronizationContext müssen Sie sich nicht um Sperren kümmern. Atomare, nicht unterbrechbare Codeabschnitte erstrecken sich grob von einem Warten zum nächsten. Achten Sie darauf, dass die Daten des gemeinsam genutzten Dienstes bei jedem Warten in einem konsistenten Zustand sind, und beachten Sie, dass aufeinander folgende Anfragen von einem Client nicht in der Reihenfolge beantwortet werden können, in der sie gesendet wurden.

Auf Client-Seite, die asynchrone Service-Betrieb ist awaitable:

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

Es ist nicht möglich aus oder ref Parameter im Betrieb Vertrag zu verwenden. Alle Antwortdaten müssen mit dem zurückgegebenen Wert Task (T) übergeben werden.
Ich benutze diese Schnittstelle in AsyncWcfLib, unterstützt eine Actor based programming model.

1

Sie weisen zu Recht darauf hin, dass async/await um Methoden herum aufgebaut sind, die Task und Task zurückgeben (für eine großartige Erklärung der Funktionsweise von async/await, siehe here). Hier ist, wie Task-basierte Methoden für einen WCF-Dienst generieren:

  1. Visual Studio 2012 RC hat eine zusätzliche Check-Box in dem "Configure-Service Reference" Dialog: "Gene Aufgabe basierte Operationen". Obwohl ich diese Option nicht in der MSDN dokumentiert sehe, erwarte ich, dass es speziell besteht, nahtlose async/warten auf WCF-Aufrufe zu ermöglichen.

  2. Für frühere Versionen, werfen Sie einen Blick auf this post, beschreibt eine Erweiterung, die Aufgabe <> basierte Methoden auf WCF sogar mit dem CTP ermöglicht.

Verwandte Themen