Freigeben über


Asynchrones Remoting

Die asynchrone Programmierung in einem Remotingszenario ist nahezu identisch mit der asynchronen Programmierung in einer einzigen Anwendungsdomäne bzw. einem einzigen Kontext. Ausnahmen bilden hier die Konfiguration und die Anforderungen für .NET Remoting selbst. Ein umfassendes Beispiel für die Verwendung von .NET Remoting sowie synchroner und asynchroner Delegaten finden Sie unter Remotingbeispiel: Asynchrones Remoting.

Ebenso wie die asynchrone Programmierung in nur einer Anwendungsdomäne bedeutet die Verwendung der asynchronen Programmierung in einem .NET Remoting-Szenario Folgendes:

  • Der Aufrufer entscheidet, ob ein Remoteaufruf asynchron ist.
  • Remotetypen müssen asynchrones Verhalten ihrer Clients nicht ausdrücklich unterstützen.
  • Die Laufzeit erzwingt vollständige Typsicherheit.
  • Sie müssen die System.Threading-Objekte ordnungsgemäß verwenden, um zu warten oder Methoden zu synchronisieren.

Bei einer Anwendung, die Aufrufe über die Grenzen von Anwendungsdomänen oder Kontexten hinweg ausführt, ist es für .NET Remoting jedoch erforderlich, das .NET Remoting-System zu konfigurieren und sicherzustellen, dass auch das Clientprogrammiermodell als Ziel eines Remoteaufrufs geeignet ist. Dies hat einen ganz einfachen Grund: Wenn Sie mit asynchronen Aufrufen arbeiten, könnten Sie ohne Weiteres eine Rückruffunktion verwenden, die das .NET Remoting-System vom Server aufruft. Wenn Sie z. B. einen Delegaten an eine statische Methode (also eine nicht remotefähige Methode) übergeben oder vergessen, einen Anschluss für den Channel auf "0" zu setzen (um die automatische Auswahl eines Clientports durch das System zu ermöglichen), wird u. U. der Aufruf an den Server abgeschlossen, Sie haben jedoch keine Möglichkeit, das Ergebnis abzurufen, da der Rückruf an den Client nicht abgeschlossen wird.

Der Client muss MarshalByRefObject nicht erweitern oder selbst irgendeinen Remotetyp konfigurieren, muss aber sonst denselben Regeln folgen wie jeder Remotetyp, der als Server verwendet werden soll:

  • Eine Instanz muss die Rückruffunktion empfangen.
  • Ein Channel muss für die Überwachung der Rückruffunktion registriert sein.

Paradigma für die asynchrone Programmierung

Die asynchrone Programmierung stellt einen ebenso einfachen Prozess wie das Programmieren einer einzelnen Anwendungsdomäne dar:

  1. Erstellen Sie eine Instanz eines Objekts, das einen Remoteaufruf einer Methode empfangen kann.
  2. Umfassen Sie diese Instanzmethode in einem AsyncDelegate-Objekt.
  3. Binden Sie die Remotemethode in einen anderen Delegaten ein.
  4. Rufen Sie die BeginInvoke-Methode für den zweiten Delegaten auf, und übergeben Sie Argumente, den AsyncDelegate und ein Objekt zum Speichern des Zustands (bzw. einen NULL-Verweis oder Nothing in Visual Basic).
  5. Warten Sie, bis das Serverobjekt die Rückrufmethode aufruft.

Dies ist die grundsätzliche Vorgehensweise, die Sie aber bis zu einem gewissen Grad variieren können. Wenn Sie zu einem bestimmten Zeitpunkt auf die Rückgabe eines bestimmten Aufrufs warten, nehmen Sie lediglich die vom Aufruf von BeginInvoke zurückgegebene IAsyncResult-Schnittstelle an, rufen die WaitHandle-Instanz für dieses Objekt ab und rufen anschließend die WaitOne-Methode auf, wie im folgenden Codebeispiel veranschaulicht.

Dim RemoteCallback As New AsyncCallback(AddressOf Me.OurCallBack)
Dim RemoteDel As New RemoteAsyncDelegate(AddressOf obj.RemoteMethod)
Dim RemAr As IAsyncResult = RemoteDel.BeginInvoke(RemoteCallback, Nothing)
RemAr.AsyncWaitHandle.WaitOne()
[C#]
AsyncCallback RemoteCallback = new AsyncCallback(this.OurCallBack);
RemoteAsyncDelegate RemoteDel = new RemoteAsyncDelegate(obj.RemoteMethod);
IAsyncResult RemAr = RemoteDel.BeginInvoke(RemoteCallback, null);
RemAr.AsyncWaitHandle.WaitOne();

Sie können jedoch auch in einer Schleife warten, die überprüft, ob der Aufruf abgeschlossen wurde. Sie können auch System.Threading-Primitive wie die ManualResetEvent-Klasse verwenden und anschließend den Aufruf selbst fertig stellen.

Dim RemoteCallback As New AsyncCallback(AddressOf Me.OurCallBack)
Dim RemoteDel As New RemoteAsyncDelegate(AddressOf obj.RemoteMethod)
Dim RemAr As IAsyncResult = RemoteDel.BeginInvoke(RemoteCallback, Nothing)
If RemAr.IsCompleted Then
  Dim del As RemoteAsyncDelegate = CType(CType(RemAr, AsyncResult).AsyncDelegate, RemoteAsyncDelegate)
  Console.WriteLine(("**SUCCESS**: Result of the remote AsyncCallBack: " _
    + del.EndInvoke(RemAr)))
' Allow the callback thread to interrupt the primary thread to execute the callback.
Thread.Sleep(1)
End If ' Do something.

[C#]
AsyncCallback RemoteCallback = new AsyncCallback(this.OurCallBack);
RemoteAsyncDelegate RemoteDel = new RemoteAsyncDelegate(obj.RemoteMethod);
IAsyncResult RemAr = RemoteDel.BeginInvoke(RemoteCallback, null);
if (RemAr.IsCompleted){
  RemoteAsyncDelegate del = (RemoteAsyncDelegate)((AsyncResult) RemAr).AsyncDelegate;
  Console.WriteLine("**SUCCESS**: Result of the remote AsyncCallBack: "  
    + del.EndInvoke(RemAr) );
// Allow the callback thread to interrupt the primary thread to execute the callback.
Thread.Sleep(1);
}

Schließlich können Sie den Hauptthread ein ManualResetEvent erstellen und auf die Rückruffunktion warten lassen, die dann das ManualResetEvent als letzte Zeile vor der Rückgabe signalisiert. Ein Beispiel für diese Art des Wartens finden Sie in den Quellcodekommentaren unter Remotingbeispiel: Asynchrones Remoting.

Schwierigkeiten

Wenn es sich beim Client um eine kontextgebundene Klasse handelt, die einen synchronisierten Kontext benötigt, wird die Rückruffunktion über die .NET Remoting-Kontextinfrastruktur gesendet. Das bedeutet, dass die Rückruffunktion selbst in Bezug auf den entsprechenden Aufrufer für derartige Kontexte asynchron ausgeführt werden kann. Dies ist auch das Verhalten des OneWayAttribute-Attributs beim Ergänzen von Signaturen für Rückrufmethoden. Jede derartige Methodenrückruffunktion kann in Bezug auf den Remoteaufrufer synchron oder asynchron ausgeführt werden, und der Aufrufer kann keine Annahmen zum Abschluss eines solchen Aufrufs machen, wenn er wieder die Kontrolle über die Ausführung erhält.

Zudem ist der Aufruf der EndInvoke-Methode vor dem erneuten Abschluss der asynchronen Operation mit demselben IAsyncResult nicht definiert.

Siehe auch

Übersicht über .NET Remoting | Remotingbeispiel: Asynchrones Remoting | Konfiguration