Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Das ereignisbasierte asynchrone Muster bietet Ihnen eine effektive Methode, um asynchrones Verhalten in Klassen mit einer vertrauten Ereignis- und Delegatsemantik verfügbar zu machen. Um ereignisbasiertes asynchrones Muster zu implementieren, müssen Sie bestimmte Verhaltensanforderungen erfüllen. In den folgenden Abschnitten werden Die Anforderungen und Richtlinien beschrieben, die Sie berücksichtigen sollten, wenn Sie eine Klasse implementieren, die dem ereignisbasierten asynchronen Muster folgt.
Eine Übersicht finden Sie unter Implementieren des ereignisbasierten asynchronen Musters.
Erforderliche Verhaltensgarantien
Wenn Sie das ereignisbasierte asynchrone Muster implementieren, müssen Sie eine Reihe von Garantien bereitstellen, um sicherzustellen, dass sich Ihre Klasse ordnungsgemäß verhält, und Clients Ihrer Klasse können sich auf dieses Verhalten verlassen.
Fertigstellung
Rufen Sie immer den MethodNameCompleted-Ereignishandler auf, wenn der Abschluss erfolgreich ist, ein Fehler auftritt oder eine Stornierung erfolgt. Anwendungen sollten niemals auf eine Situation treffen, in der sie im Leerlauf bleiben und ein Abschluss niemals erfolgt. Eine Ausnahme dieser Regel ist, wenn der asynchrone Vorgang selbst so konzipiert ist, dass er nie abgeschlossen wird.
Abgeschlossenes Event und EventArgs
Wenden Sie für jede separate MethodNameAsync-Methode die folgenden Entwurfsanforderungen an:
Definieren Sie ein MethodName Completed-Ereignis für dieselbe Klasse wie die Methode.
Definieren Sie eine EventArgs Klasse und einen zugehörigen Delegaten für das MethodNameCompleted-Ereignis , das von der AsyncCompletedEventArgs Klasse abgeleitet wird. Der Standardklassenname sollte der Form MethodNameCompletedEventArgs sein.
Stellen Sie sicher, dass die EventArgs Klasse spezifisch für die Rückgabewerte der MethodName-Methode ist. Wenn Sie die EventArgs Klasse verwenden, sollte niemals verlangt werden, dass Entwickler das Ergebnis casten.
Das folgende Codebeispiel zeigt eine gute und schlechte Implementierung dieser Entwurfsanforderung.
// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
DemoType result = e.Result;
}
// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
DemoType result = (DemoType)(e.Result);
}
Definieren Sie keine EventArgs-Klasse zum Zurückgeben von Methoden, die
void
zurückgeben. Verwenden Sie stattdessen eine Instanz der AsyncCompletedEventArgs Klasse.Stellen Sie sicher, dass Sie immer das MethodNameCompleted-Ereignis auslösen. Dieses Ereignis sollte beim erfolgreichen Abschluss, bei einem Fehler oder beim Abbruch ausgelöst werden. Anwendungen sollten niemals auf eine Situation treffen, in der sie im Leerlauf bleiben und ein Abschluss niemals erfolgt.
Stellen Sie sicher, dass Sie alle Ausnahmen abfangen, die im asynchronen Vorgang auftreten, und weisen Sie der Eigenschaft die Error abgefangene Ausnahme zu.
Wenn beim Abschließen der Aufgabe ein Fehler aufgetreten ist, sollten auf die Ergebnisse nicht zugegriffen werden. Wenn die Error Eigenschaft nicht
null
ist, stellen Sie sicher, dass der Zugriff auf eine Eigenschaft in der EventArgs Struktur eine Ausnahme auslöst. Verwenden Sie die RaiseExceptionIfNecessary Methode, um diese Überprüfung durchzuführen.Simuliere ein Timeout als Fehler. Wenn es zu einem Timeout kommt, lösen Sie das MethodNameCompleted-Ereignis aus und weisen der Eigenschaft TimeoutException eine Error zu.
Wenn Ihre Klasse mehrere gleichzeitige Aufrufe unterstützt, stellen Sie sicher, dass das MethodNameCompleted-Ereignis das entsprechende
userSuppliedState
Objekt enthält.Stellen Sie sicher, dass das MethodNameCompleted-Ereignis im entsprechenden Thread und zum entsprechenden Zeitpunkt im Anwendungslebenszyklus ausgelöst wird. Weitere Informationen finden Sie im Abschnitt "Threading" und "Kontexte".
Gleichzeitiges Ausführen von Vorgängen
Wenn Ihre Klasse mehrere gleichzeitige Aufrufe unterstützt, ermöglichen Sie es dem Entwickler, jeden Aufruf separat nachzuverfolgen, indem Sie die MethodNameAsync-Überladung definieren, die einen objektwertigen Statusparameter oder eine Aufgaben-ID verwendet, der
userSuppliedState
genannt wird. Dieser Parameter sollte immer der letzte Parameter in der Signatur der MethodNameAsync-Methode sein.Wenn Ihre Klasse die MethodNameAsync-Überladung definiert, die einen Parameter für den Objektwertzustand oder eine Aufgaben-ID verwendet, achten Sie darauf, die Lebensdauer des Vorgangs mit dieser Aufgaben-ID nachzuverfolgen, und stellen Sie sicher, dass sie wieder im Abschlusshandler bereitgestellt wird. Es stehen Hilfsklassen zur Unterstützung zur Verfügung. Weitere Informationen zur Parallelitätsverwaltung finden Sie unter Vorgehensweise: Implementieren einer Komponente, die das ereignisbasierte asynchrone Muster unterstützt.
Wenn Ihre Klasse die MethodName Async-Methode ohne den Zustandsparameter definiert und nicht mehrere gleichzeitige Aufrufe unterstützt, stellen Sie sicher, dass jeder Versuch, MethodNameAsync aufzurufen, bevor der vorherige Aufruf von MethodNameAsync abgeschlossen wurde, eine InvalidOperationExceptionAusgelöst wird.
Lösen Sie im Allgemeinen keine Ausnahme aus, wenn die MethodNameAsync-Methode ohne den
userSuppliedState
Parameter mehrmals aufgerufen wird, sodass mehrere ausstehende Vorgänge vorhanden sind. Sie können eine Ausnahme auslösen, wenn Ihre Klasse diese Situation explizit nicht verarbeiten kann, sollten jedoch davon ausgehen, dass Entwickler mit diesen mehreren nicht unterscheidbaren Rückrufen umgehen können.
Zugreifen auf Ergebnisse
Wenn während der Ausführung des asynchronen Vorgangs ein Fehler aufgetreten ist, sollten auf die Ergebnisse nicht zugegriffen werden. Stellen Sie sicher, dass beim Zugriff auf eine Eigenschaft in AsyncCompletedEventArgs die Ausnahme, auf die von Error verwiesen wird, ausgelöst wird, wenn
null
nicht Error ist. Die AsyncCompletedEventArgs Klasse stellt die RaiseExceptionIfNecessary Methode für diesen Zweck bereit.Stellen Sie sicher, dass jeder Versuch, auf das Ergebnis zuzugreifen, eine InvalidOperationException Meldung auslöst, dass der Vorgang abgebrochen wurde. Verwenden Sie die AsyncCompletedEventArgs.RaiseExceptionIfNecessary Methode, um diese Überprüfung durchzuführen.
Fortschrittsberichte
Unterstützen Sie die Statusberichterstattung, sofern möglich. Auf diese Weise können Entwickler eine bessere Benutzererfahrung für Anwendungen bereitstellen, wenn sie Ihre Klasse verwenden.
Wenn Sie ein ProgressChanged - oder MethodNameProgressChanged-Ereignis implementieren, stellen Sie sicher, dass keine solchen Ereignisse für einen bestimmten asynchronen Vorgang ausgelöst werden, nachdem das MethodNameCompleted-Ereignis dieses Vorgangs ausgelöst wurde.
** Wenn der Standard ProgressChangedEventArgs aufgefüllt wird, stellen Sie sicher, dass ProgressPercentage immer als Prozentsatz interpretiert werden kann. Der Prozentsatz muss nicht korrekt sein, sollte aber einen Prozentsatz darstellen. Wenn Ihre Statusberichtsmetrik einen anderen Wert als einen Prozentsatz haben muss, leiten Sie eine Klasse von der ProgressChangedEventArgs-Klasse ab und belassen Sie ProgressPercentage bei 0. Vermeiden Sie die Verwendung einer anderen Berichtsmetrik als einem Prozentsatz.
Stellen Sie sicher, dass das
ProgressChanged
Ereignis im entsprechenden Thread und zum entsprechenden Zeitpunkt im Anwendungslebenszyklus ausgelöst wird. Weitere Informationen finden Sie im Abschnitt "Threading" und "Kontexte".
IsBusy-Implementierung
Machen Sie eine
IsBusy
Eigenschaft nicht verfügbar, wenn Ihre Klasse mehrere gleichzeitige Aufrufe unterstützt. Beispielsweise geben XML-Webdienstproxys keineIsBusy
-Eigenschaft preis, da sie mehrere gleichzeitige Aufrufe asynchroner Methoden unterstützen.Die
IsBusy
-Eigenschaft solltetrue
zurückkehren, nachdem die MethodNameAsync-Methode aufgerufen wurde und bevor das MethodNameCompleted-Ereignis ausgelöst wurde. Andernfalls sollte esfalse
zurückgeben. Die Komponenten BackgroundWorker und WebClient sind Beispiele für Klassen, die eineIsBusy
Eigenschaft bereitstellen.
Abbruch
Unterstützen Sie einen Abbruch, wenn möglich. Auf diese Weise können Entwickler eine bessere Benutzererfahrung für Anwendungen bereitstellen, wenn sie Ihre Klasse verwenden.
Im Fall eines Abbruchs legen Sie das Cancelled-Flag im AsyncCompletedEventArgs-Objekt fest.
Stellen Sie sicher, dass jeder Versuch, auf das Ergebnis zuzugreifen, eine InvalidOperationException Meldung auslöst, dass der Vorgang abgebrochen wurde. Verwenden Sie die AsyncCompletedEventArgs.RaiseExceptionIfNecessary Methode, um diese Überprüfung durchzuführen.
Stellen Sie sicher, dass die Aufrufe an eine Abbruchmethode immer erfolgreich zurückgegeben werden und niemals eine Ausnahme auslösen. Im Allgemeinen wird ein Kunde nicht darüber informiert, ob ein Vorgang zu einem bestimmten Zeitpunkt wirklich storniert werden kann und nicht darüber benachrichtigt wird, ob eine zuvor ausgestellte Kündigung erfolgreich war. Die Anwendung erhält jedoch immer eine Benachrichtigung, wenn ein Abbruch erfolgreich war, da die Anwendung am Abschlussstatus teilnimmt.
Lösen Sie das MethodNameCompleted-Ereignis aus, wenn der Vorgang abgebrochen wird.
Fehler und Ausnahmen
- Fangen Sie alle Ausnahmen ab, die im asynchronen Vorgang auftreten, und legen Sie den Wert der AsyncCompletedEventArgs.Error-Eigenschaft auf diese Ausnahme fest.
Threading und Kontexte
Für den korrekten Betrieb der Klasse ist es wichtig, dass die Ereignishandler des Clients für den richtigen Thread oder Kontext für das angegebene Anwendungsmodell aufgerufen werden, einschließlich ASP.NET- und Windows Forms-Anwendungen. Es werden zwei wichtige Hilfsklassen bereitgestellt, um sicherzustellen, dass sich ihre asynchrone Klasse unter jedem Anwendungsmodell ordnungsgemäß verhält: AsyncOperation und AsyncOperationManager.
AsyncOperationManager stellt eine Methode bereit, CreateOperation, die ein AsyncOperation zurückgibt. Ihre MethodNameAsync-Methode ruft CreateOperation auf und Ihre Klasse nutzt die zurückgegebene AsyncOperation, um die Lebensdauer der asynchronen Aufgabe nachzuverfolgen.
Für einen Statusbericht, inkrementelle Ergebnisse und Abschluss auf dem Client rufen Sie die Methoden Post und OperationCompleted in AsyncOperation auf. AsyncOperation ist für das Marshalling von Aufrufen an die Ereignishandler des Clients an den richtigen Thread oder Kontext verantwortlich.
Hinweis
Sie können diese Regeln umgehen, wenn Sie explizit gegen die Richtlinie des Anwendungsmodells vorgehen möchten, aber dennoch von den anderen Vorteilen der Verwendung des ereignisbasierten asynchronen Musters profitieren. Möglicherweise möchten Sie zum Beispiel, dass eine in Windows Forms betriebene Klasse eine Freethread-Klasse ist. Sie können eine kostenlose Threadklasse erstellen, solange Entwickler die implizierten Einschränkungen verstehen. Konsolenanwendungen synchronisieren nicht die Ausführung von Post Aufrufen. Dies kann dazu führen, dass ProgressChanged
Ereignisse außerhalb der Reihenfolge ausgelöst werden. Wenn Sie die serialisierte Ausführung von Post Aufrufen wünschen, implementieren und installieren Sie eine System.Threading.SynchronizationContext Klasse.
Weitere Informationen darüber, wie Sie AsyncOperation und AsyncOperationManager zur Unterstützung Ihrer asynchronen Vorgänge verwenden, finden Sie in So implementieren Sie eine Komponente, die das ereignisbasierte asynchrone Muster unterstützt.
Leitlinien
Im Idealfall sollte jeder Aufruf der Methode unabhängig von anderen sein. Vermeiden Sie die Kopplung von Aufrufen mit gemeinsam genutzten Ressourcen. Wenn Ressourcen für Aufrufe freigegeben werden sollen, müssen Sie in Ihrer Implementierung einen ordnungsgemäßen Synchronisierungsmechanismus bereitstellen.
Von Designs, bei denen der Kunde die Synchronisierung implementieren muss, wird abgeraten. Beispielsweise könnten Sie eine asynchrone Methode haben, die ein globales statisches Objekt als Parameter empfängt. mehrere gleichzeitige Aufrufe einer solchen Methode können zu Datenbeschädigungen oder Deadlocks führen.
Wenn Sie eine Methode mit der Überladung mit mehrfachem Aufruf (
userState
in der Signatur) implementieren, muss Ihre Klasse eine Sammlung von Benutzerzuständen oder Aufgaben-IDs und deren entsprechenden ausstehenden Vorgängen verwalten. Diese Sammlung sollte durchlock
Bereiche geschützt werden, da die verschiedenen AufrufeuserState
Objekte in der Sammlung hinzufügen und entfernen.Erwägen Sie,
CompletedEventArgs
Klassen nach Möglichkeit und angemessen wiederzuverwenden. In diesem Fall ist die Benennung nicht mit dem Methodennamen konsistent, da ein bestimmter Delegat und EventArgs Typ nicht an eine einzelne Methode gebunden sind. Dennoch ist es niemals akzeptabel, Entwickler zu zwingen, den von einer Eigenschaft in EventArgs abgerufenen Wert umzuwandeln.Wenn Sie eine Klasse erstellen, die von Component abgeleitet wird, implementieren und installieren Sie Ihre eigene SynchronizationContext Klasse nicht. Anwendungsmodelle, nicht Komponenten, steuern die verwendete SynchronizationContext.
Wenn Sie Multithreading jeglicher Art verwenden, machen Sie sich potenziell sehr schwerwiegenden und komplexen Fehlern aus. Bevor Sie eine Lösung implementieren, die Multithreading verwendet, lesen Sie bewährte Methoden für verwaltete Threadings.
Siehe auch
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementieren des ereignisbasierten asynchronen Musters
- Ereignisbasiertes asynchrones Muster (EAP)
- Entscheiden, wann das ereignisbasierte asynchrone Muster implementiert werden soll
- Bewährte Methoden für die Implementierung des ereignisbasierten asynchronen Musters
- Vorgehensweise: Verwenden von Komponenten, die das ereignisbasierte asynchrone Muster unterstützen
- Vorgehensweise: Implementieren einer Komponente, die das ereignisbasierte asynchrone Muster unterstützt