Operacje synchroniczne i asynchroniczne
W tym temacie omówiono implementowanie i wywoływanie operacji usługi asynchronicznej.
Wiele aplikacji wywołuje metody asynchronicznie, ponieważ umożliwia aplikacji kontynuowanie przydatnej pracy podczas uruchamiania wywołania metody. Usługi i klienci programu Windows Communication Foundation (WCF) mogą uczestniczyć w wywołaniach operacji asynchronicznych na dwóch odrębnych poziomach aplikacji, co zapewnia aplikacjom WCF jeszcze większą elastyczność w celu zmaksymalizowania równowagi przepływności przed interakcyjnością.
Typy operacji asynchronicznych
Wszystkie kontrakty usług w programie WCF, niezależnie od typów parametrów i wartości zwracanych, użyj atrybutów programu WCF, aby określić określony wzorzec wymiany komunikatów między klientem a usługą. Program WCF automatycznie kieruje komunikaty przychodzące i wychodzące do odpowiedniej operacji usługi lub uruchamiania kodu klienta.
Klient posiada tylko kontrakt usługi, który określa wzorzec wymiany komunikatów dla określonej operacji. Klienci mogą zaoferować deweloperom dowolny wybrany przez nich model programowania, tak długo, jak zaobserwowano podstawowy wzorzec wymiany komunikatów. Dlatego też usługi mogą implementować operacje w dowolny sposób, o ile określony wzorzec komunikatu jest obserwowany.
Niezależność kontraktu usługi od implementacji usługi lub klienta umożliwia wykonywanie asynchroniczne w aplikacjach WCF:
Klienci mogą asynchronicznie wywoływać operacje żądań/odpowiedzi przy użyciu synchronicznej wymiany komunikatów.
Usługi mogą implementować operację żądania/odpowiedzi asynchronicznie przy użyciu synchronicznej wymiany komunikatów.
Wymiana komunikatów może być jednokierunkowa, niezależnie od implementacji klienta lub usługi.
Sugerowane scenariusze asynchroniczne
Użyj asynchronicznego podejścia w implementacji operacji usługi, jeśli implementacja usługi operacji wykonuje wywołanie blokujące, takie jak wykonywanie operacji we/wy. Jeśli jesteś w implementacji operacji asynchronicznej, spróbuj wywołać operacje asynchroniczne i metody, aby rozszerzyć ścieżkę wywołania asynchronicznego tak daleko, jak to możliwe. Na przykład wywołaj metodę BeginOperationTwo()
z poziomu .BeginOperationOne()
Użyj podejścia asynchronicznego w kliencie lub wywołującej aplikację w następujących przypadkach:
W przypadku wywoływania operacji z poziomu aplikacji warstwy środkowej. (Aby uzyskać więcej informacji na temat takich scenariuszy, zobacz Aplikacje klienckie warstwy środkowej).
Jeśli wywołasz operacje na stronie ASP.NET, użyj stron asynchronicznych.
W przypadku wywoływania operacji z dowolnej aplikacji, która jest wątek, takich jak Windows Forms lub Windows Presentation Foundation (WPF). W przypadku korzystania z modelu wywoływania asynchronicznego opartego na zdarzeniach zdarzenie wynikowe jest wywoływane w wątku interfejsu użytkownika, dodając czas odpowiedzi do aplikacji bez konieczności samodzielnego obsługi wielu wątków.
Ogólnie rzecz biorąc, jeśli masz wybór między wywołaniem synchronicznym i asynchronicznym, wybierz wywołanie asynchroniczne.
Implementowanie operacji usługi asynchronicznej
Operacje asynchroniczne można zaimplementować przy użyciu jednej z trzech następujących metod:
Wzorzec asynchroniczny oparty na zadaniach
Wzorzec asynchroniczny oparty na zdarzeniach
Wzorzec asynchroniczny IAsyncResult
Wzorzec asynchroniczny oparty na zadaniach
Wzorzec asynchroniczny oparty na zadaniach jest preferowanym sposobem implementowania operacji asynchronicznych, ponieważ jest to najprostszy i najbardziej prosty sposób. Aby użyć tej metody, po prostu zaimplementuj operację usługi i określ zwracany typ zadania<T>, gdzie T jest typem zwracanym przez operację logiczną. Na przykład:
public class SampleService:ISampleService
{
// ...
public async Task<string> SampleMethodTaskAsync(string msg)
{
return Task<string>.Factory.StartNew(() =>
{
return msg;
});
}
// ...
}
Operacja SampleMethodTaskAsync zwraca ciąg> zadania<, ponieważ operacja logiczna zwraca ciąg. Aby uzyskać więcej informacji na temat wzorca asynchronicznego opartego na zadaniach, zobacz Wzorzec asynchroniczny oparty na zadaniach.
Ostrzeżenie
W przypadku korzystania ze wzorca asynchronicznego opartego na zadaniach wyjątek T:System.AggregateException może zostać zgłoszony, jeśli wystąpi wyjątek podczas oczekiwania na zakończenie operacji. Ten wyjątek może wystąpić na kliencie lub usługach
Wzorzec asynchroniczny oparty na zdarzeniach
Usługa, która obsługuje asynchroniczny wzorzec oparty na zdarzeniach, będzie miała co najmniej jedną operację o nazwie MethodNameAsync. Te metody mogą dublowania wersji synchronicznych, które wykonują tę samą operację w bieżącym wątku. Klasa może również mieć zdarzenie MethodNameCompleted i może mieć metodę MethodNameAsyncCancel (lub po prostu CancelAsync). Klient, który chce wywołać operację, zdefiniuje procedurę obsługi zdarzeń, która ma zostać wywołana po zakończeniu operacji.
Poniższy fragment kodu ilustruje sposób deklarowania operacji asynchronicznych przy użyciu wzorca asynchronicznego opartego na zdarzeniach.
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.
}
Aby uzyskać więcej informacji na temat wzorca asynchronicznego opartego na zdarzeniach, zobacz Wzorzec asynchroniczny oparty na zdarzeniach.
Wzorzec asynchroniczny IAsyncResult
Operację usługi można zaimplementować w sposób asynchroniczny przy użyciu asynchronicznego wzorca programowania programu .NET Framework i oznaczania <Begin>
metody AsyncPattern z właściwością ustawioną na true
. W takim przypadku operacja asynchroniczna jest uwidaczniona w metadanych w tej samej postaci co operacja synchroniczna: jest uwidoczniona jako pojedyncza operacja z komunikatem żądania i skorelowanym komunikatem odpowiedzi. Modele programowania klientów mają wtedy wybór. Mogą one reprezentować ten wzorzec jako operację synchroniczną lub asynchroniczną, tak długo, jak usługa jest wywoływana wymiana komunikatów żądań.
Ogólnie rzecz biorąc, ze względu na asynchroniczny charakter systemów nie należy stosować zależności od wątków. Najbardziej niezawodnym sposobem przekazywania danych do różnych etapów przetwarzania wysyłania operacji jest użycie rozszerzeń.
Aby zapoznać się z przykładem, zobacz How to: Implement an Asynchronous Service Operation (Instrukcje: implementowanie asynchronicznej operacji usługi).
Aby zdefiniować operację X
kontraktu wykonywaną asynchronicznie niezależnie od tego, jak jest wywoływana w aplikacji klienckiej:
Zdefiniuj dwie metody przy użyciu wzorca
BeginOperation
iEndOperation
.Metoda
BeginOperation
zawierain
parametry iref
dla operacji i zwraca IAsyncResult typ.Metoda
EndOperation
zawiera IAsyncResult parametr orazout
parametry iref
i zwraca typ zwracany przez operacje.
Zobacz na przykład następującą 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
Aby utworzyć operację asynchroniczną, dwie metody to:
[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
Uwaga
Atrybut OperationContractAttribute jest stosowany tylko do BeginDoWork
metody . Wynikowy kontrakt ma jedną operację WSDL o nazwie DoWork
.
Wywołania asynchroniczne po stronie klienta
Aplikacja kliencka WCF może używać dowolnego z trzech asynchronicznych modeli wywoływania opisanych wcześniej
W przypadku korzystania z modelu opartego na zadaniach wystarczy wywołać operację przy użyciu słowa kluczowego await, jak pokazano w poniższym fragmencie kodu.
await simpleServiceClient.SampleMethodTaskAsync("hello, world");
Użycie wzorca asynchronicznego opartego na zdarzeniach wymaga tylko dodania programu obsługi zdarzeń w celu otrzymania powiadomienia o odpowiedzi — a wynikowe zdarzenie jest automatycznie wywoływane w wątku interfejsu użytkownika. Aby użyć tej metody, określ opcje polecenia /async i /tcv:Version35 za pomocą narzędzia ServiceModel Metadata Tool (Svcutil.exe), jak w poniższym przykładzie.
svcutil http://localhost:8000/servicemodelsamples/service/mex /async /tcv:Version35
Po wykonaniu tej czynności Svcutil.exe generuje klasę klienta WCF z infrastrukturą zdarzeń, która umożliwia aplikacji wywołującej zaimplementowanie i przypisanie programu obsługi zdarzeń w celu odebrania odpowiedzi i podjęcia odpowiednich działań. Pełny przykład można znaleźć w temacie How to: Call Service Operations Asynchronously (Instrukcje: wywoływanie operacji usługi asynchronicznie).
Model asynchroniczny oparty na zdarzeniach jest jednak dostępny tylko w programie .NET Framework 3.5. Ponadto nie jest obsługiwana nawet w programie .NET Framework 3.5, gdy kanał klienta programu WCF jest tworzony przy użyciu programu System.ServiceModel.ChannelFactory<TChannel>. W przypadku obiektów kanału klienta programu WCF należy używać System.IAsyncResult obiektów do asynchronicznego wywoływania operacji. Aby użyć tego podejścia, określ /async opcji polecenia za pomocą narzędzia ServiceModel Metadata Tool (Svcutil.exe), jak w poniższym przykładzie.
svcutil http://localhost:8000/servicemodelsamples/service/mex /async
Spowoduje to wygenerowanie kontraktu usługi, w którym każda operacja jest modelowana jako <Begin>
metoda z AsyncPattern właściwością ustawioną na true
i odpowiednią <End>
metodą. Pełny przykład użycia elementu ChannelFactory<TChannel>można znaleźć w temacie How to: Call Operations Asynchronously Using a Channel Factory (Jak wywoływać operacje asynchronicznie przy użyciu fabryki kanałów).
W obu przypadkach aplikacje mogą wywoływać operację asynchronicznie, nawet jeśli usługa jest implementowana synchronicznie, w taki sam sposób, jak aplikacja może używać tego samego wzorca do wywoływania asynchronicznej lokalnej metody synchronicznej. Sposób implementacji operacji nie ma znaczenia dla klienta; po nadejściu komunikatu odpowiedzi jego zawartość jest wysyłana do metody asynchronicznej <End>
klienta, a klient pobiera informacje.
Wzorce wymiany komunikatów jednokierunkowych
Można również utworzyć asynchroniczny wzorzec wymiany komunikatów, w którym operacje jednokierunkowe (operacje, dla których OperationContractAttribute.IsOneWay nie ma true
skorelowanej odpowiedzi) mogą być wysyłane w obu kierunkach przez klienta lub usługę niezależnie od drugiej strony. (Używa to wzorca dwukierunkowej wymiany komunikatów z komunikatami jednokierunkowymi). W takim przypadku kontrakt usługi określa jednokierunkową wymianę komunikatów, która może implementować asynchroniczne wywołania lub implementacje albo nie, zgodnie z potrzebami. Ogólnie rzecz biorąc, gdy kontrakt jest wymianą komunikatów jednokierunkowych, implementacje mogą być w dużej mierze asynchroniczne, ponieważ po wysłaniu komunikatu aplikacja nie czeka na odpowiedź i może kontynuować wykonywanie innych czynności.
Asynchroniczne klienci i kontrakty komunikatów oparte na zdarzeniach
Wytyczne dotyczące projektowania dla modelu asynchronicznego opartego na zdarzeniach stwierdzają, że jeśli zwracana jest więcej niż jedna wartość, jedna wartość jest zwracana jako Result
właściwość, a pozostałe są zwracane jako właściwości obiektu EventArgs . Jednym z tych wyników jest to, że jeśli klient importuje metadane przy użyciu opcji polecenia asynchronicznego opartego na zdarzeniach, a operacja zwraca więcej niż jedną wartość, obiekt domyślny EventArgs zwraca jedną wartość jako Result
właściwość, a pozostałe są właściwościami EventArgs obiektu.
Jeśli chcesz otrzymać obiekt komunikatu jako Result
właściwość i mieć zwrócone wartości jako właściwości tego obiektu, użyj /messageContract opcji polecenia. Spowoduje to wygenerowanie podpisu zwracającego komunikat odpowiedzi jako Result
właściwość EventArgs obiektu. Wszystkie wewnętrzne wartości zwracane są właściwościami obiektu komunikatu odpowiedzi.