Freigeben über


Empfänger und Empfängerketten

Clients machen Methodenaufrufe für Remoteobjekte, indem sie Nachrichten an die Remoteanwendungsdomäne senden. Dies erfolgt durch eine Gruppe von Channelobjekten. Die Clientanwendungsdomäne enthält einen Clientchannel, und die Remoteanwendungsdomäne enthält einen Remotechannel. Jeder Channel besteht aus einer Reihe von Channelempfängern, die in einer Kette miteinander verknüpft sind. Die folgende Abbildung zeigt die Struktur einer Basis-Channelempfängerkette.

Basis-Channelempfängerkette

Empfänger und Empfängerketten

Vor dem Senden oder nach dem Empfang einer Nachricht senden Channels jede Nachricht durch eine Kette von Channelempfängerobjekten. Diese Empfängerkette enthält Empfänger, die für die Grundfunktionen des Channels erforderlich sind, wie z. B. Formatierungsprogramm-, Transport- oder Stapelgeneratorempfänger. Sie können die Channelempfängerkette jedoch anpassen, um mit einer Nachricht oder einem Stream besondere Aufgaben auszuführen. Jeder Channelempfänger implementiert entweder IClientChannelSink oder IServerChannelSinkfrlrfSystemRuntimeRemotingChannelsIServerChannelSinkClassTopic. Der erste Channelempfänger des Clients muss auch IMessageSinkfrlrfSystemRuntimeRemotingMessagingIMessageSinkClassTopic implementieren. Er implementiert in der Regel IClientFormatterSink (erbt von IMessageSink, IChannelSinkBase und IClientChannelSink) und wird als Formatierungsempfänger bezeichnet, weil er die eingehende Nachricht in einen Stream (ein IMessagefrlrfSystemRuntimeRemotingMessagingIMessageClassTopic-Objekt) umwandelt.

Die Channelempfängerkette verarbeitet alle Nachrichten, die an eine oder von einer Anwendungsdomäne gesendet werden. Ein Channelempfänger hat Zugriff auf die Nachricht, die verarbeitet wird. Bei der nachfolgenden Verarbeitung wird die Nachricht verwendet, die nach der Verarbeitung an das System zurückgegeben wurde. Dies ist eine natürliche Stelle, um einen Protokollierungsdienst oder irgendeine Art von Filter zu implementieren.

Jeder Channelempfänger verarbeitet den Stream und übergibt ihn anschließend an den nächsten Channelempfänger. Das bedeutet, dass die Empfänger vor oder nach einem bestimmten Empfänger wissen müssen, was mit dem an sie übergebenen Stream zu tun ist.

NoteHinweis:

Nachrichtenempfänger dürfen keine Ausnahmen auslösen. Eine Methode, mit der ein Nachrichtenempfänger dies steuern kann, besteht darin, den Methodencode in try-catch-Blöcke einzubinden.

Channelempfängeranbieter (Objekte, die die Schnittstelle IClientChannelSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientChannelSinkProviderClassTopic, IClientFormatterSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientFormatterSinkProviderClassTopic oder IServerChannelSinkProvider implementieren) sind für die Erstellung der Channelempfängers zuständig, die .NET-Remotenachrichten verarbeiten. Beim Aktivieren eines Remotetyps wird der Channelempfänger aus dem Channel abgerufen, und die CreateSink-Methode wird für den Empfängeranbieter aufgerufen, um den ersten Channelempfänger aus der Kette abzurufen.

Die Nachrichtenübertragung zwischen Client und Server erfolgt über Channelempfänger. Channelempfänger werden auch in einer Kette miteinander verknüpft. Wenn die CreateSink-Methode für einen Empfängeranbieter aufgerufen wird, sollte sie Folgendes ausführen:

  • Einen Channelempfänger erstellen.

  • CreateSink für den nächsten Empfängeranbieter in der Kette aufrufen.

  • Sicherstellen, dass der nächste Empfänger und der aktuelle Empfänger miteinander verknüpft sind.

  • Den Empfänger an den Aufrufer zurückgeben.

Channelempfänger sind dafür zuständig, alle an sie gerichteten Aufrufe an den nächsten Empfänger in der Kette weiterzuleiten. Außerdem müssen sie einen Mechanismus zum Speichern eines Verweises auf den nächsten Empfänger bereitstellen.

Channelempfänger sind bei dem, was sie entlang der Empfängerkette senden, sehr flexibel. So können z. B. Sicherheitsempfänger, die die Authentifizierung vor dem Senden der eigentlichen serialisierten, ursprünglichen Nachricht aushandeln, die ganze Channelnachricht nehmen, den Inhalt des Streams durch ihren eigenen Inhalt ersetzen und ihn entlang der Empfängerkette zur Remoteanwendungsdomäne senden. Bei der Rückübertragung kann der Sicherheitsempfänger die Antwortnachricht abfangen und damit eine Konversation mit den entsprechenden Sicherheitsempfängern in der Remoteanwendungsdomäne beginnen. Nachdem eine Vereinbarung getroffen wurde, kann der ursprüngliche Sicherheitsempfänger den ursprünglichen Inhaltsdatenstrom an die Remoteanwendungsdomäne senden.

Nachrichtenverarbeitung in der Channelempfängerkette

Nachdem das .NET-Remotesystem einen Channel gefunden hat, der die Nachricht verarbeiten kann, übergibt der Channel die Nachricht an den Formatierungsempfänger, indem er

SyncProcessMessage (oder AsyncProcessMessage) aufruft. Der Formatierungsempfänger erstellt das Transportheaderarray und ruft GetRequestStream für den nächsten Empfänger auf. Dieser Aufruf wird entlang der Empfängerkette weitergeleitet, und jeder Empfänger kann einen Anforderungsstream erstellen, der wieder an den Formatierungsempfänger übergeben wird. Wenn GetRequestStream einen null-Verweis (Nothing in Visual Basic) zurückgibt, erstellt der Formatierungsempfänger einen eigenen Empfänger, der für die Serialisierung verwendet werden soll. Nachdem die Rückgabe für diesen Aufruf erfolgt ist, wird die Nachricht serialisiert. Anschließend wird für den ersten Channelempfänger in der Empfängerkette die entsprechende Verarbeitungsmethode für die Nachricht aufgerufen.

Empfänger können keine Daten in den Stream schreiben, können aber Daten aus dem Stream lesen oder bei Bedarf einen neuen Stream weiterleiten. Empfänger können dem Headerarray auch Header hinzufügen (wenn sie nicht zuvor GetRequestStream für den nächsten Empfänger aufgerufen haben) und sich selbst dem Empfängerstapel hinzufügen, bevor sie den Aufruf an den nächsten Empfänger weiterleiten. (Der Synchronisierungsstapel wird verwendet, damit asynchrone Aufrufe nach deren Abschluss einen Rückruf an den Aufrufer ausführen können.) Wenn der Aufruf den Transportempfänger am Ende der Kette erreicht, sendet der Transportempfänger die Header und die serialisierte Nachricht über den Channel an den Server, wo der gesamte Prozess umgekehrt wird. Der Transportempfänger (auf dem Server) ruft die Header und die serialisierte Nachricht von der Serverseite des Streams ab und leitet diese durch die Empfängerkette bis zum Formatierungsempfänger weiter. Der Formatierungsempfänger deserialisiert die Nachricht und leitet sie an das .NET-Remotesystem weiter, wo die Nachricht wieder in einen Methodenaufruf umgewandelt und am Serverobjekt aufgerufen wird.

Erstellen von Channelempfängerketten

Zum Erstellen eines neuen Channelempfängers müssen Sie das .NET-Remotesystem so implementieren und konfigurieren, dass es eine IServerChannelSinkProvider-Implementierung oder eine IClientChannelSinkProvider-Implementierung erkennt, die die benutzerdefinierte IClientChannelSink-Implementierung oder die IServerChannelSink-Implementierung erstellen oder den nächsten Empfänger in der Kette abrufen kann. Sie können die abstrakte BaseChannelSinkWithProperties-Klasse verwenden, um die benutzerdefinierten Channelempfänger zu implementieren.

Erstellen eines Channelempfängeranbieters

Beim Erstellen eines Channels können Anwendungen Server- oder Client-Channelempfängeranbieter als Parameter bereitstellen. Channelempfängeranbieter müssen in einer Kette gespeichert werden, und der Entwickler muss alle Channelempfängeranbieter verketten, bevor der Äußerste an den Channelkonstruktor übergeben wird. Der Channelempfängeranbieter implementiert für diesen Zweck eine Next-Eigenschaft. Das folgende Codebeispiel veranschaulicht die Erstellung eines Client-Channelempfängeranbieters. Ein vollständiges Beispiel finden Sie unter Remotingbeispiel: Channelempfängeranbieter.

private Function CreateDefaultClientProviderChain() As IClientChannelSinkProvider
   Dim chain As New FirstClientFormatterSinkProvider            
   Dim sink As IClientChannelSinkProvider
   sink = chain
   sink.Next = New SecondClientFormatterSinkProvider
   sink = sink.Next
   return chain
End Function 

private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 
NoteHinweis:

Wenn in einer Konfigurationsdatei mehrere Channelempfängeranbieter angegeben sind, werden diese vom .NET-Remotesysteme in der Reihenfolge verkettet, in der sie in der Konfigurationsdatei gefunden werden. Die Channelempfängeranbieter werden erstellt, wenn der Channel während des Aufrufs von Configure erstellt wird.

Formatierungsempfänger

Formatierungsempfänger serialisieren die Channelnachricht als Objekt, das IMessage implementiert, in den Nachrichtenstream. Manche Implementierungen von Formatierungsempfängern verwenden die vom System bereitgestellten Formatierungstypen (BinaryFormatterfrlrfSystemRuntimeSerializationFormattersBinaryBinaryFormatterClassTopic und SoapFormatterfrlrfSystemRuntimeSerializationFormattersSoapSoapFormatterClassTopic). Andere Implementierungen verfügen über eigene Möglichkeiten, um die Channelnachricht in den Stream zu transformieren.

Die Funktion des Formatierungsempfängers besteht darin, die erforderlichen Header zu erstellen und die Nachricht in den Stream zu serialisieren. Nach Erreichen des Formatierungsempfängers wird die Nachricht über den SyncProcessMessage-Aufruf oder den AsyncProcessMessage-Aufruf an alle Empfänger in der Channelempfängerkette weitergeleitet. In dieser Phase wurde die Nachricht bereits serialisiert und kann nicht geändert werden.

NoteHinweis:

Empfänger, die die Nachricht selbst erstellen oder ändern müssen, müssen in der Empfängerkette vor dem Formatierungsprogramm platziert werden. Dies wird ganz einfach durch eine Implementierung von IClientFormatterSink erreicht. Dadurch wird dem System mitgeteilt, dass es einen Verweis auf den Formatierungsempfänger besitzt. Der eigentliche Formatierungsempfänger kann dann weiter hinten in der Empfängerkette platziert werden.

Bei der Rückübertragung transformiert der Formatierungsempfänger den Nachrichtenstream wieder in das Objekt der Channelnachricht (Rückgabenachricht). Der erste Empfänger des Clients muss die IClientFormatterSink-Schnittstelle implementieren. Wenn CreateSink****an den Channel zurückgegeben wird, wird der zurückgegebene Verweis in einen IClientFormatterSink-Typ umgewandelt, sodass die SyncProcessMessage-Methode aufgerufen werden kann. Beachten Sie, dass IClientFormatterSink von IMessageSink abgeleitet ist. Wenn die Umwandlung fehlschlägt, löst das System eine Ausnahme aus.

Benutzerdefinierte Channelempfänger

Auf dem Client werden benutzerdefinierte Channelempfänger zwischen dem Formatierungsempfänger und dem letzten Transportempfänger in die Objektkette eingefügt. Wenn Sie einen benutzerdefinierten Channelempfänger in den Client- oder Serverchannel einfügen, können Sie IMessage an einer der folgenden Stellen verarbeiten:

  • Während des Prozesses, bei dem ein als Nachricht dargestellter Aufruf in einen Stream konvertiert und über die Verbindung übertragen wird.

  • Während des Prozesses, bei dem ein Stream aus der Verbindung genommen und an den letzten Nachrichtenempfänger vor dem Remoteobjekt auf dem Server oder dem Proxyobjekt (auf dem Client) gesendet wird.

Abhängig davon, ob es sich um einen ausgehenden oder einen eingehenden Aufruf handelt, können benutzerdefinierte Empfänger Daten aus dem Stream lesen oder in den Stream schreiben und den Headern nach Bedarf zusätzliche Information hinzufügen. In dieser Phase wurde die Nachricht bereits vom Formatierungsprogramm serialisiert und kann nicht geändert werden. Wenn der Nachrichtenaufruf an den Transportempfänger am Ende der Kette weitergeleitet wird, schreibt der Transportempfänger die Header in den Stream und leitet den Stream mit dem vom Channel vorgegebenen Transportprotokoll an den Transportempfänger auf dem Server weiter.

Transportempfänger

Der Transportempfänger ist auf dem Client der letzte Empfänger in der Kette und auf dem Server der erste Empfänger in der Kette. Der Transportempfänger überträgt nicht nur die serialisierte Nachricht, sondern er ist darüber hinaus für das Senden der Header an den Server sowie das Abrufen der Header und des Streams zuständig, wenn ein Aufruf vom Server zurückgegeben wird. Diese Empfänger sind in den Channel integriert und können nicht erweitert werden.

Ersetzen des Standardformatierungsprogramms

Da es sich bei einem Channel um einen abstrakten Netzwerkmechanismus handelt, können Sie das .NET-Remotesystem so konfigurieren, dass ein vom System implementierter Channel mit einem Formatierungsprogramm Ihrer Wahl kombiniert werden kann. Verwenden Sie dazu den Channelkonstruktor, der eine IDictionary-Implementierung der Channeleigenschaften, ein Formatierungsprogramm auf dem Server und ein Formatierungsprogramm auf dem Client annimmt. Sie können das Formatierungsprogramm auch in einer Konfigurationsdatei angeben. Im folgenden Beispiel wird das .NET-Remotekonfigurationssystem angewiesen, BinaryClientFormatterSink zu erstellen, auf dem Client aber HttpChannel zu verwenden.

<configuration>
   <system.runtime.remoting>
      <application>
         <channels>
            <channel ref="http">
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
         <channels>
      </application>
   </system.runtime.remoting>
</configuration> 

Der folgende Code macht das Gleiche programmgesteuert, setzt aber den Remoteschnittstellentyp IService**** voraus, der GetServerString und GetServerTime implementiert:

Imports System
Imports System.Collections
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http

Public Class ClientProcess
  <MTAThread()> _
  Public Shared Sub Main()
      
    ' Note that any name/value pairs of configuration attributes can be 
    ' placed in this dictionary (the configuration system calls this same 
    ' constructor).
    Dim properties As New Hashtable()
    properties("name") = "HttpBinary"
     
    ChannelServices.RegisterChannel(New HttpChannel(properties, New BinaryClientFormatterSinkProvider(), Nothing))
    ' The last parameter above (Nothing) is the server sink provider chain 
    ' to obtain the default behavior (which includes SOAP and 
    ' binary formatters on the server side).
    Dim service As IService = CType(Activator.GetObject(GetType(IService), "http://computer:8080/SAService"), IService)
      
    Console.WriteLine("Server string is: " + service.GetServerString())
    Console.WriteLine("Server time is: " + service.GetServerTime())
  End Sub
   
End Class 

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

public class ClientProcess{

  public static void Main(string[] Args){
        
    // Note that any name/value pairs of configuration attributes can be 
    // placed in this dictionary (the configuration system calls this 
    // same HttpChannel constructor).
    IDictionary properties = new Hashtable();
    properties["name"] = "HttpBinary";

    // The last parameter below is the server sink provider chain 
    // to obtain the default behavior (which includes SOAP and binary 
    // formatters) on the server side.
    ChannelServices.RegisterChannel(new HttpChannel(properties, new BinaryClientFormatterSinkProvider(), null));

    IService service = (IService)Activator.GetObject(typeof(IService),"http://computer:8080/SAService");
        
    Console.WriteLine("Server string is: " + service.GetServerString());
    Console.WriteLine("Server time is: " + service.GetServerTime());      
  }
}

Ein vollständiges Beispiel für diese Kombination aus Channel und Formatierungsprogramm, die in Internetinformationsdiensten (Internet Information Services, IIS) gehostet wird, finden Sie unter Remotingbeispiel: Hosting in Internetinformationsdiensten (IIS).

Wenn dieser Client ein TcpChannel-Objekt mit dem SoapClientFormatterSinkfrlrfSystemRuntimeRemotingChannelsSoapClientFormatterSinkClassTopic-Objekt verwenden soll, brauchen Sie nur die Namespaces und den RegisterChannel****-Aufruf wie im folgenden Code gezeigt zu ändern:

ChannelServices.RegisterChannel(New TcpChannel(properties, New SoapClientFormatterSinkProvider(), Nothing))

ChannelServices.RegisterChannel(new TcpChannel(properties, new SoapClientFormatterSinkProvider(), null));

Siehe auch

Konzepte

Hosten von Remoteobjekten in Internetinformationsdiensten (IIS)
Remotingbeispiel: Hosting in Internetinformationsdiensten (IIS)

Weitere Ressourcen

Remoting für Fortgeschrittene

Footer image

Copyright © 2007 by Microsoft Corporation. Alle Rechte vorbehalten.