Remotefähige Objekte

Remotefähige Objekte können gut in einer weit verteilten Umgebung verwendet werden. Es gibt zwei Hauptarten von remotefähigen Objekten:

  • MBV (Marshal-by-Value)-Objekte, die kopiert und aus der Anwendungsdomäne heraus übergeben werden, und
  • MBR (Marshal-by-Reference)-Objekte, für die ein Proxy erstellt und vom Client für den Remotezugriff auf das Objekt verwendet wird.

MBV (Marshal-By-Value)-Objekte

MBV (Marshal-by-Value)-Objekte deklarieren ihre Serialisierungsregeln (entweder, indem sie ISerializable zum Implementieren der eigenen Serialisierung implementieren oder indem sie durch SerializableAttribute ergänzt werden, wodurch das System angewiesen wird, das Objekt automatisch zu serialisieren), aber sie erweitern nicht MarshalByRefObject. Das Remotingsystem erstellt eine vollständige Kopie dieser Objekte und übergibt die Kopie an die aufrufende Anwendungsdomäne. Sobald sich die Kopie in der Anwendungsdomäne des Aufrufers befindet, erfolgen Aufrufe der Kopie direkt an diese. Wenn MBV-Objekte als Argumente übergeben werden, werden sie außerdem als Wert übergeben. Außer SerializableAttribute zu deklarieren oder ISerializable zu implementieren, müssen Sie nichts weiter tun, damit Instanzen der Klasse als Wert über Anwendungs- und Kontextgrenzen hinweg übergeben werden.

Hinweis   Ab Version 1.1 von .NET Framework führt die Remotinginfrastruktur die Deserialisierung bestimmter Typen auf dem Server nicht mehr automatisch durch. Wenn dies auch in Ihrem Szenario der Fall ist, müssen Sie die Deserialisierungsebene des Servers auf Full festlegen, bevor der Server das MBV-Objekt deserialisieren und verwenden kann. Weitere Informationen finden Sie unter Automatische Deserialisierung in .NET Remoting.

Verwenden Sie MBV-Objekte, wenn aus Leistungs- oder Verarbeitungsgründen das Verschieben des vollständigen Status des Objekts und aller ausführbaren Funktionen in die Zielanwendungsdomäne sinnvoll ist. In vielen Szenarien kann so die Anzahl zeitraubender, zahlreiche Ressourcen in Anspruch nehmender Roundtrips über Netzwerk-, Prozess- und Anwendungsdomänengrenzen hinweg reduziert werden. MBV-Objekte können auch direkt von innerhalb der ursprünglichen Anwendungsdomäne des Objekts verwendet werden. In diesem Fall wird keine Kopie erstellt, da kein Marshalling stattfindet, und der Zugriff erfolgt äußerst effizient.

Es ist jedoch auch nicht unbedingt ratsam, eine vollständige Kopie über ein ausgelastetes Netzwerk zu übergeben, wenn die veröffentlichten Objekte sehr groß sind. Und es werden auch keine Änderungen des Status des kopierten Objekts wieder an das ursprüngliche Objekt in der ursprünglichen Anwendungsdomäne zurückgegeben. Auf einer abstrakten Ebene ähnelt dieses Szenario dem einer statischen HTML-Seite, die von einem Clientbrowser angefordert wird. Der Server kopiert die Datei, schreibt sie in einen Stream, versendet und vergisst sie. Jede nachfolgende Anforderung ist dann lediglich eine weitere Anforderung für eine andere Kopie.

Das Remotingsystem verwendet sehr häufig serialisierbare Objekte. Ein Verweis auf ein Objekt in einer anderen Anwendungsdomäne, im Remotingsystem anhand der ObjRef-Klasse dargestellt, ist selbst serialisierbar. Es muss möglich sein, eine exakte Kopie zu erstellen und diese an eine Anforderung zu senden. Meldungsobjekte, die IMessage implementieren, da sie generische Container von Aufrufinformationen und sonstigen erforderlichen Objektverweisen sind. Außerdem handelt es sich bei Objekten, die problemlos Daten übertragen, häufig um serialisierbare Objekte. DataSet z. B. erweitert die MarshalByValueComponent-Klasse, die ISerializable implementiert.

Benutzerdefinierte Ausnahmen bei Remoting

Systemdefinierte Ausnahmen sind immer Marshal-by-Value-Typen (sie implementieren die ISerializable-Schnittstelle), die beim Auslösen durch ein Remoteobjekt automatisch zum Aufrufer kopiert werden, wenn die Remotingkonfiguration dies zulässt. (Ab Version 1.1 von .NET Framework muss das <customErrors>-Element auf off festgelegt werden, damit Ausnahmen an den Aufrufer geleitet werden können.)

Zum Erstellen eigener Ausnahmetypen, die von Remoteobjekten ausgelöst und von Remoteaufrufern abgefangen werden können, müssen folgende Schritte ausgeführt werden:

  1. Sie können ISerializable implementieren.
  2. Platzieren Sie das SerializableAttribute-Attribut in der Klasse.
  3. Implementieren Sie einen Deserialisierungskonstruktor, der ein SerializationInfo-Objekt und ein StreamingContext-Objekt als Parameter annimmt.

Das folgende C#-Codebeispiel enthält eine einfache Implementierung, die bei ordnungsgemäßer Konfiguration zurück zum Aufrufer kopiert wird, wenn sie vom Remoteserverobjekt ausgelöst wird.

[Serializable]
public class CustomRemotableException : RemotingException, ISerializable {
   private string _internalMessage;

   public CustomRemotableException(){
      _internalMessage = String.Empty;
   }
   
   public CustomRemotableException(string message){
      _internalMessage = message;
   }
   
   public CustomRemotableException(SerializationInfo info, StreamingContext context){
      _internalMessage = (string)info.GetValue("_internalMessage", typeof(string));
   }

   public override void GetObjectData(SerializationInfo info, StreamingContext context){
      info.AddValue("_internalMessage", _internalMessage);
   }

   // Returns the exception information. 
   public override string Message{
      get {
            return "This is your custom remotable exception returning: \"" 
      + _internalMessage 
      + "\"";
      }
   }
}

MBR (Marshal-By-Reference)-Objekte

MBR (Marshal-by-Reference)-Objekte sind remotefähige Objekte, die mindestens System.MarshalByRefObject erweitern. Wenn ein Client eine Instanz eines MBR-Objekts in der eigenen Anwendungsdomäne erstellt, erstellt die .NET Remoting-Infrastruktur abhängig vom Typ der deklarierten Aktivierung in der Anwendungsdomäne des Aufrufers ein Proxyobjekt, das das MBR-Objekt darstellt, und gibt einen Verweis auf diesen Proxy an den Aufrufer zurück. Der Client ruft anschließend den Proxy auf. Remoting marshallt diese Aufrufe, sendet sie zurück an die ursprüngliche Anwendungsdomäne und startet den Aufruf des eigentlichen Objekts.

Hinweis   Wenn sich der Client in derselben Anwendungsdomäne befindet wie das MBR-Objekt, gibt die Infrastruktur an den Client einen direkten Verweis auf das MBR-Objekt zurück und verhindert so, dass unnötiges Marshalling ausgeführt wird.

Wenn ein MarshalByRefObject als Parameter übergeben wird, wird es zu einem Proxy in der anderen Anwendungsdomäne, wenn der Aufruf eintrifft. MBR-Rückgabewerte und out-Parameter funktionieren auf dieselbe Weise.

Hinweis   Ab Version 1.1 von .NET Framework führt die Remotinginfrastruktur die Deserialisierung bestimmter Typen auf dem Server nicht mehr automatisch durch. Um Unterstützung für MBR-Objekten zu erhalten, die als Parameter übergeben werden, muss die Deserialisierungsebene des Servers auf Full festgelegt werden, bevor der Server den MBR-Parameter deserialisieren und verwenden kann. Weitere Informationen über dieses und andere Szenarios finden Sie unter Automatische Deserialisierung in .NET Remoting.

Verwenden Sie MBR-Objekte, wenn der Status des Objekts und alle ausführbaren Funktionen in der Anwendungsdomäne bleiben sollen, in der sie erstellt wurden. So sollte z. B. ein Objekt, das ein internes Feld enthält, bei dem es sich um ein Handle des Betriebssystems handelt, MarshalByRefObject erweitern, da das Handle des Betriebssystems in einer anderen Anwendungsdomäne in einem anderen Prozess oder auf einem anderen Computer keine Bedeutung hätte. Manchmal kann ein Objekt von großem Umfang sein. Bei einem robusten Server spielt dies keine Rolle, aber die Übertragung an ein 33,6 KB/s-Modem dürfte Probleme bereiten.

Kontextgebundene Objekte

Kontextgebundene Objekte sind MBR-Objekte, die von System.ContextBoundObject erben, das wiederum von System.MarshalByRefObject erbt. Einen Kontext können Sie sich als Untereinheit einer Anwendungsdomäne vorstellen, die eine leistungsfähige Umgebung für Objekte bereitstellt, die sich während der Ausführung in ihr befinden. Beispielsweise kann ein Kontext garantieren, dass auf die Objekte nicht von mehreren Threads gleichzeitig zugegriffen wird. Jede Anwendungsdomäne weist einen Standardkontext auf. Verwalteter Code erstellt meist Objekte und ruft Member direkt von derselben Anwendungsdomäne aus auf. Dabei wird der Standardkontext der Domäne verwendet, so dass keine kontextbezogenen Aspekte zu berücksichtigen sind. Alle Typen, die von ContextBoundObject erben, werden anderen Kontexten als Proxys offen gelegt (unabhängig davon, ob sie sich in derselben oder in anderen Domänen befinden).

Stellen Sie sich z. B. einmal vor, Sie hätten eine Methode für einen Typ, der Teil einer Transaktion und somit durch Regeln eingeschränkt ist, die spezifisch für den Kontext sind, in dem die Erstellung stattfand. Dieser Typ muss von ContextBoundObject erben, so dass auf das Objekt von seinem eigenen Kontext aus zugegriffen wird und das System die Regeln in Bezug auf die Transaktionen erzwingen kann, die mit dem Objekt und seinen Methoden verknüpft sind. Wenn ein ContextBoundObject von einem anderen Kontext innerhalb derselben Anwendungsdomäne aufgerufen wird, wird für den Aufrufer ein Proxy erstellt, aber die kontextübergreifende Kommunikation findet nicht über das Channelsystem statt und steigert somit in dieser Situation die Aufrufeffizienz.

Da das Überschreiten von Grenzen Prozessorzeit in Anspruch nimmt, empfiehlt es sich, die vom Objekt zu überschreitenden Grenzen zu bestimmen und eine Entscheidung darüber zu treffen, welchen Typ eines remotefähigen Objekts der Server darstellen soll. Auf Objekte, die für einen bestimmten Kontext spezifisch sind, kann nur direkt von diesem Kontext aus zugegriffen werden. Dasselbe gilt für Objekte, die für eine bestimmte Anwendungsdomäne spezifisch sind. Um diese Objekte zu verschieben, muss das Remotingsystem erfolgreich eine Kontextgrenze, eine Anwendungsgrenze oder gar beide überwinden, bevor das Serverobjekt von innerhalb der für das Objekt spezifischen Grenze aufgerufen werden kann. Wenn für das Aufrufen des Objekts keine Überprüfung des Kontexts erforderlich ist, sollten Sie verhindern, dass der Remotetyp ContextBoundObject erweitert, da in diesem Fall MarshalByRefObject vorzuziehen ist. Falls eine Überprüfung erforderlich sein sollte, sollten Sie ContextBoundObject erweitern. Bedenken Sie jedoch, dass die zusätzliche Grenze erst überwunden werden muss, bevor der Aufruf für das Objekt erfolgen kann.

Siehe auch

Remotefähige und nicht remotefähige Objekte | ContextBoundObject | Nicht remotefähige Objekte