Dela via


Synkrona och asynkrona åtgärder

I det här avsnittet beskrivs hur du implementerar och anropar asynkrona tjänståtgärder.

Många program anropar metoder asynkront eftersom det gör att programmet kan fortsätta att utföra användbart arbete medan metodanropet körs. Windows Communication Foundation-tjänster (WCF) och klienter kan delta i asynkrona åtgärdsanrop på två olika nivåer i programmet, vilket ger WCF-program ännu mer flexibilitet för att maximera dataflödet som balanseras mot interaktivitet.

Typer av asynkrona åtgärder

Alla tjänstkontrakt i WCF, oavsett parametertyper och returvärden, använder WCF-attribut för att ange ett visst mönster för meddelandeutbyte mellan klient och tjänst. WCF dirigerar automatiskt inkommande och utgående meddelanden till lämplig tjänståtgärd eller kör klientkod.

Klienten har endast tjänstkontraktet, som anger mönstret för meddelandeutbyte för en viss åtgärd. Klienter kan erbjuda utvecklaren vilken programmeringsmodell de vill, så länge det underliggande mönstret för meddelandeutbyte observeras. Det gör också att tjänster kan implementera åtgärder på något sätt, så länge det angivna meddelandemönstret observeras.

Tjänstkontraktets oberoende från antingen tjänst- eller klientimplementeringen möjliggör följande former av asynkron körning i WCF-program:

  • Klienter kan anropa begärande-/svarsåtgärder asynkront med hjälp av ett synkront meddelandeutbyte.

  • Tjänster kan implementera en begäran/svar-åtgärd asynkront med hjälp av ett synkront meddelandeutbyte.

  • Meddelandeutbyten kan vara enkelriktade, oavsett implementering av klienten eller tjänsten.

Föreslagna asynkrona scenarier

Använd en asynkron metod i en tjänståtgärdsimplementering om implementeringen av åtgärdstjänsten gör ett blockerande anrop, till exempel att utföra I/O-arbete. När du är i en asynkron åtgärdsimplementering kan du försöka anropa asynkrona åtgärder och metoder för att utöka den asynkrona anropssökvägen så långt som möjligt. Du kan till exempel anropa en BeginOperationTwo() inifrån BeginOperationOne().

  • Använd en asynkron metod i en klient eller ett anropande program i följande fall:

  • Om du anropar åtgärder från ett mellannivåprogram. (Mer information om sådana scenarier finns i Klientprogram på mellannivå.)

  • Om du anropar åtgärder på en ASP.NET sida använder du asynkrona sidor.

  • Om du anropar åtgärder från ett program som är entrådat, till exempel Windows Forms eller Windows Presentation Foundation (WPF). När du använder den händelsebaserade asynkrona samtalsmodellen aktiveras resultathändelsen i användargränssnittstråden, vilket lägger till svarstider i programmet utan att du behöver hantera flera trådar själv.

  • Om du i allmänhet har ett val mellan ett synkront och asynkront anrop väljer du det asynkrona anropet.

Implementera en asynkron tjänståtgärd

Asynkrona åtgärder kan implementeras med någon av följande tre metoder:

  1. Det aktivitetsbaserade asynkrona mönstret

  2. Det händelsebaserade asynkrona mönstret

  3. Asynkront IAsyncResult-mönster

Aktivitetsbaserat asynkront mönster

Det aktivitetsbaserade asynkrona mönstret är det bästa sättet att implementera asynkrona åtgärder eftersom det är det enklaste och enklaste. Om du vill använda den här metoden implementerar du helt enkelt din tjänståtgärd och anger en returtyp för Aktivitet<T>, där T är den typ som returneras av den logiska åtgärden. Till exempel:

public class SampleService:ISampleService
{
   // ...
   public async Task<string> SampleMethodTaskAsync(string msg)
   {
      return Task<string>.Factory.StartNew(() =>
      {
         return msg;
      });
   }
   // ...
}

Åtgärden SampleMethodTaskAsync returnerar aktivitetssträngen<> eftersom den logiska åtgärden returnerar en sträng. Mer information om det aktivitetsbaserade asynkrona mönstret finns i Det aktivitetsbaserade asynkrona mönstret.

Varning

När du använder det aktivitetsbaserade asynkrona mönstret kan en T:System.AggregateException utlösas om ett undantag inträffar i väntan på att åtgärden ska slutföras. Det här undantaget kan inträffa på klienten eller tjänsterna

Händelsebaserat asynkront mönster

En tjänst som stöder det händelsebaserade asynkrona mönstret har en eller flera åtgärder med namnet MethodNameAsync. Dessa metoder kan spegla synkrona versioner som utför samma åtgärd på den aktuella tråden. Klassen kan också ha en MethodNameCompleted-händelse och den kan ha en MethodNameAsyncCancel-metod (eller helt enkelt CancelAsync). En klient som vill anropa åtgärden definierar en händelsehanterare som ska anropas när åtgärden slutförs.

Följande kodfragment visar hur du deklarerar asynkrona åtgärder med hjälp av det händelsebaserade asynkrona mönstret.

public class AsyncExample
{
    // Synchronous methods.
    public int Method1(string param);
    public void Method2(double param);

    // Asynchronous methods.
    public void Method1Async(string param);
    public void Method1Async(string param, object userState);
    public event Method1CompletedEventHandler Method1Completed;

    public void Method2Async(double param);
    public void Method2Async(double param, object userState);
    public event Method2CompletedEventHandler Method2Completed;

    public void CancelAsync(object userState);

    public bool IsBusy { get; }

    // Class implementation not shown.
}

Mer information om det händelsebaserade asynkrona mönstret finns i Det händelsebaserade asynkrona mönstret.

Asynkront IAsyncResult-mönster

En tjänståtgärd kan implementeras på ett asynkront sätt med hjälp av .NET Framework-asynkrona programmeringsmönster och markera <Begin> metoden med AsyncPattern egenskapen inställd på true. I det här fallet exponeras den asynkrona åtgärden i metadata i samma form som en synkron åtgärd: Den exponeras som en enda åtgärd med ett begärandemeddelande och ett korrelerat svarsmeddelande. Klientprogrammeringsmodeller har sedan ett val. De kan representera det här mönstret som en synkron åtgärd eller som en asynkron åtgärd, så länge som när tjänsten anropas sker ett utbyte av begärandesvarsmeddelanden.

I allmänhet bör du inte vara beroende av trådarna med systemens asynkrona karaktär. Det mest tillförlitliga sättet att skicka data till olika faser i bearbetningen av driftssändning är att använda tillägg.

Ett exempel finns i Så här implementerar du en Asynkron tjänståtgärd.

Så här definierar du en kontraktsåtgärd X som körs asynkront oavsett hur den anropas i klientprogrammet:

  • Definiera två metoder med hjälp av mönstret BeginOperation och EndOperation.

  • Metoden BeginOperation innehåller in och ref parametrar för åtgärden och returnerar en IAsyncResult typ.

  • Metoden EndOperation innehåller en IAsyncResult parameter samt parametrarna out och ref och returnerar åtgärdsreturtypen.

Se till exempel följande metod.

int DoWork(string data, ref string inout, out string outonly)
Function DoWork(ByVal data As String, ByRef inout As String, _out outonly As out) As Integer

För att skapa en asynkron åtgärd skulle de två metoderna vara:

[OperationContract(AsyncPattern=true)]
IAsyncResult BeginDoWork(string data,
                         ref string inout,
                         AsyncCallback callback,
                         object state);
int EndDoWork(ref string inout, out string outonly, IAsyncResult result);
<OperationContract(AsyncPattern := True)>
Function BeginDoWork(ByVal data As String, _
                     ByRef inout As String, _
                     ByVal callback As AsyncCallback, _
                     ByVal state As Object) As IAsyncResult
Function EndDoWork(ByRef inout As String, ByRef outonly As String, ByVal result As IAsyncResult) As Integer

Kommentar

Attributet OperationContractAttribute tillämpas endast på BeginDoWork metoden. Det resulterande kontraktet har en WSDL-åtgärd med namnet DoWork.

Asynkrona anrop på klientsidan

Ett WCF-klientprogram kan använda någon av tre asynkrona anropande modeller som beskrevs tidigare

När du använder den aktivitetsbaserade modellen anropar du helt enkelt åtgärden med nyckelordet await enligt följande kodfragment.

await simpleServiceClient.SampleMethodTaskAsync("hello, world");

Om du använder det händelsebaserade asynkrona mönstret måste du bara lägga till en händelsehanterare för att få ett meddelande om svaret – och den resulterande händelsen aktiveras automatiskt i användargränssnittstråden. Om du vill använda den här metoden anger du både kommandoalternativen /async och /tcv:Version35 med verktygsverktyget för ServiceModel-metadata (Svcutil.exe), som i följande exempel.

svcutil http://localhost:8000/servicemodelsamples/service/mex /async /tcv:Version35

När detta är klart genererar Svcutil.exe en WCF-klientklass med händelseinfrastrukturen som gör det möjligt för det anropande programmet att implementera och tilldela en händelsehanterare att ta emot svaret och vidta lämpliga åtgärder. Ett fullständigt exempel finns i Så här anropar du tjänståtgärder asynkront.

Den händelsebaserade asynkrona modellen är dock endast tillgänglig i .NET Framework 3.5. Dessutom stöds den inte ens i .NET Framework 3.5 när en WCF-klientkanal skapas med hjälp av en System.ServiceModel.ChannelFactory<TChannel>. Med WCF-klientkanalobjekt måste du använda System.IAsyncResult objekt för att anropa dina åtgärder asynkront. Om du vill använda den här metoden anger du kommandoalternativet /async med ServiceModel Metadata Utility Tool (Svcutil.exe), som i följande exempel.

svcutil http://localhost:8000/servicemodelsamples/service/mex /async

Detta genererar ett tjänstkontrakt där varje åtgärd modelleras som en <Begin> metod med egenskapen AsyncPattern inställd på true och en motsvarande <End> metod. Ett fullständigt exempel med hjälp av en ChannelFactory<TChannel>finns i How to: Call Operations Asynchronously Using a Channel Factory (Så här anropar du åtgärder asynkront med hjälp av en kanalfabrik).

I båda fallen kan program anropa en åtgärd asynkront även om tjänsten implementeras synkront, på samma sätt som ett program kan använda samma mönster för att anropa asynkront en lokal synkron metod. Hur åtgärden implementeras är inte viktigt för klienten. När svarsmeddelandet kommer skickas dess innehåll till klientens asynkrona <End> metod och klienten hämtar informationen.

Exchange-mönster för enkelriktade meddelanden

Du kan också skapa ett asynkront meddelandeutbytesmönster där enkelriktade åtgärder (åtgärder för vilka OperationContractAttribute.IsOneWay is true inte har något korrelerat svar) kan skickas i endera riktningen av klienten eller tjänsten oberoende av den andra sidan. (Detta använder duplex-mönstret för meddelandeutbyte med enkelriktade meddelanden.) I det här fallet anger tjänstkontraktet ett enkelriktad meddelandeutbyte som båda sidor kan implementera som asynkrona anrop eller implementeringar, eller inte, efter behov. När kontraktet är ett utbyte av enkelriktade meddelanden kan implementeringarna i stort sett vara asynkrona eftersom programmet inte väntar på ett svar när ett meddelande har skickats och kan fortsätta utföra annat arbete.

Händelsebaserade asynkrona klienter och meddelandekontrakt

Designriktlinjerna för det händelsebaserade asynkrona modelltillståndet att om mer än ett värde returneras returneras ett värde som Result egenskapen och de andra returneras som egenskaper för EventArgs objektet. Ett resultat av detta är att om en klient importerar metadata med hjälp av de händelsebaserade asynkrona kommandoalternativen och åtgärden returnerar mer än ett värde, returnerar standardobjektet EventArgs ett värde som Result egenskapen och resten är egenskaperna för EventArgs objektet.

Om du vill ta emot meddelandeobjektet som Result egenskap och har de returnerade värdena som egenskaper för objektet använder du kommandoalternativet /messageContract . Detta genererar en signatur som returnerar svarsmeddelandet som Result egenskapen på EventArgs objektet. Alla interna returvärden är sedan egenskaper för svarsmeddelandeobjektet.

Se även