Freigeben über


Erweitern von Verteilern

Verteiler sind dafür verantwortlich, eingehende Nachrichten aus den zugrunde liegenden Kanälen abzufangen, sie in Methodenaufrufe im Anwendungscode zu übersetzen und die Ergebnisse zurück an den Aufrufer zu senden. Verteilererweiterungen versetzen Sie in die Lage, diese Verarbeitung zu ändern. Sie können Nachrichten- oder Parameterinspektoren implementieren, die den Inhalt von Nachrichten oder Parametern überprüfen bzw. ändern. Sie können die Weiterleitung von Nachrichten an Vorgänge ändern oder andere Funktionalität bereitstellen.

In diesem Thema wird beschrieben, wie Klassen DispatchRuntime und DispatchOperation in einer WCF-Dienstanwendung (Windows Communication Foundation) verwendet werden, um das Standardausführungsverhalten eines Dispatchers zu ändern oder um Nachrichten, Parameter oder Rückgabewerte abzufangen oder zu ändern, bevor oder nachdem sie aus der Kanalschicht gesendet oder abgerufen werden. Weitere Informationen zur entsprechenden Nachrichtenverarbeitung durch die Client-Runtime finden Sie unter Erweitern von Clients. Informationen zum besseren Verständnis der Rolle, die IExtensibleObject<T>-Typen beim Zugriff auf gemeinsam verwendete Zustände zwischen verschiedenen Runtimeanpassungsobjekten spielen, finden Sie unter Erweiterbare Objekte.

Verteiler

Die Dienstmodellebene führt die Konvertierung zwischen dem Programmiermodell des Entwicklers und dem zugrunde liegenden Nachrichtenaustausch, gewöhnlich als Kanalschicht bezeichnet, durch. In WCF sind die Kanal- und die Endpunktdispatcher (ChannelDispatcher bzw. EndpointDispatcher) die Dienstkomponenten, die dafür verantwortlich sind, neue Kanäle zu akzeptieren, Nachrichten zu empfangen, Vorgänge zu verteilen und aufzurufen sowie Antworten zu verarbeiten. Verteilerobjekte sind empfangende Objekte, aber auch Rückrufvertragsimplementierungen in Duplexdiensten machen ihre Verteilerobjekte für Überprüfung, Änderung oder Erweiterung verfügbar.

Der Kanalverteiler (und der zugehörige IChannelListener) fangen eingehende Nachrichten aus den zugrunde liegenden Kanälen ab und übergeben diese Nachrichten ihren jeweiligen Endpunktverteilern. Jeder Endpunktverteiler hat eine DispatchRuntime, die die Nachrichten an die entsprechende DispatchOperation weiterleitet, die für den Aufruf der Methode verantwortlich ist, die den Vorgang implementiert. Dabei werden verschiedene optionale und notwendige Erweiterungsklassen aufgerufen. In diesem Thema wird erklärt, wie diese Elemente zusammenpassen, und wie Sie deren Eigenschaften ändern und eigenen Code schreiben, um die Basisfunktionalität zu erweitern.

Verteilereigenschaften und geänderte Anpassungsobjekte werden mithilfe von Dienst-, Endpunkt-, Vertrags- und Vorgangsverhaltensobjekten eingefügt. In diesem Thema wird nicht beschrieben, wie Verhaltensobjekte verwendet werden. Weitere Informationen zu den Typen, die zum Einfügen von Dispatcheränderungen verwendet werden, finden Sie unter Konfigurieren und Erweitern der Laufzeit mit Verhalten.

Die folgende Grafik bietet einen Überblick über die architektonischen Elemente in einem Dienst.

The dispatch runtime architecture

Kanalverteiler

Ein ChannelDispatcher-Objekt wird erstellt, um einen IChannelListener an einem bestimmten URI (als Abhör-URI bezeichnet) einer Instanz eines Diensts zuzuordnen. Jedes ServiceHost-Objekt kann über viele ChannelDispatcher-Objekte verfügen, die jeweils einem Listener und einem Abhör-URI zugeordnet sind. Wenn eine Nachricht eingeht, fragt der ChannelDispatcher jedes der zugeordneten EndpointDispatcher-Objekte ab, ob der Endpunkt die Nachricht akzeptieren kann, und leitet die Nachricht an den Endpunkt weiter, der dies kann.

Alle Eigenschaften, die die Lebensdauer und das Verhalten einer Kanalsitzung steuern, sind zur Überprüfung oder Änderung im ChannelDispatcher-Objekt verfügbar. Dies schließt benutzerdefinierte Kanalinitialisierer, den Kanallistener, den Host, den zugeordneten InstanceContext usw. ein.

Endpunktverteiler

Das EndpointDispatcher-Objekt ist verantwortlich für das Verarbeiten von Nachrichten von einem ChannelDispatcher, wenn die Zieladresse einer Nachricht mit der AddressFilter-Eigenschaft übereinstimmt und die Nachrichtenaktion mit der ContractFilter-Eigenschaft übereinstimmt. Wenn zwei EndpointDispatcher-Objekte eine Nachricht akzeptieren können, bestimmt der Wert der FilterPriority-Eigenschaft den Endpunkt mit höherer Priorität.

Verwenden Sie das EndpointDispatcher-Objekt, um die beiden Haupterweiterungspunkte des Dienstmodells – die DispatchRuntime-Klasse und die DispatchOperation-Klasse – abzurufen, die Sie verwenden können, um die Verarbeitung durch den Verteiler anzupassen. Die DispatchRuntime-Klasse ermöglicht Benutzern, den Verteiler im Vertragsbereich (also für alle Nachrichten in einem Vertrag) abzufangen und zu erweitern. Die DispatchOperation-Klasse ermöglicht Benutzern, den Verteiler im Vorgangsbereich (also für alle Nachrichten in einem Vorgang) abzufangen und zu erweitern.

Szenarien

Es gibt eine Reihe von Gründen, den Verteiler zu erweitern:

  • Benutzerdefinierte Nachrichtenvalidierung. Benutzer können durchsetzen, dass eine Nachricht für ein bestimmtes Schema gültig ist. Dies kann über die Implementierung der Nachrichteninterceptorschnittstellen erreicht werden. Ein Beispiel finden Sie unter Nachrichteninspektoren.

  • Benutzerdefinierte Nachrichtenprotokollierung. Benutzer können einige Anwendungsnachrichten prüfen und protokollieren, die durch einen Endpunkt fließen. Dies kann ebenfalls mit den Nachrichteninterceptorschnittstellen erreicht werden.

  • Benutzerdefinierte Nachrichtentransformationen. Benutzer können bestimmte Transformationen (beispielsweise die Versionsverwaltung) auf die Nachricht in der Laufzeit anwenden. Auch dies kann mit den Nachrichteninterceptorschnittstellen erreicht werden.

  • Benutzerdefiniertes Datenmodell. Benutzer*innen können ein Datenserialisierungsmodell verwenden, das sich von den standardmäßig in WCF unterstützten Modellen (System.Runtime.Serialization.DataContractSerializer, System.Xml.Serialization.XmlSerializer und unformatierte Nachrichten) unterscheidet. Dies kann über die Implementierung der Nachrichtenformatierungsschnittstellen erreicht werden. Ein Beispiel finden Sie unter Vorgangsformatierer und Vorgangsauswahl.

  • Benutzerdefinierte Parametervalidierung. Benutzer können durchsetzen, dass typisierte Parameter gültig sind (im Gegensatz zu XML). Dies kann mit den Parameterinspektorschnittstellen erreicht werden.

  • Benutzerdefinierte Vorgangsverteilung. Benutzer können die Verteilung an etwas anderes als an eine Aktion implementieren – beispielsweise an das Textelement oder an eine benutzerdefinierte Nachrichteneigenschaft. Dies kann über die Verwendung der IDispatchOperationSelector-Schnittstelle erreicht werden. Ein Beispiel finden Sie unter Vorgangsformatierer und Vorgangsauswahl.

  • Objektpooling. Benutzer können Instanzen zusammenlegen, statt für jeden Aufruf eine neue Instanz zuzuordnen. Dies kann über die Implementierung der Instanzanbieterschnittstellen erreicht werden. Ein Beispiel finden Sie unter Pooling.

  • Instanzleasing. Benutzer können ein Leasingmuster ähnlich dem von .NET Framework Remoting für die Lebensdauer der Instanz implementieren. Dies kann mit den Instanzkontextlebensdauer-Schnittstellen erreicht werden.

  • Benutzerdefinierte Fehlerbehandlung. Benutzer können steuern, wie lokale Fehler verarbeitet werden und wie Clients über Fehler unterrichtet werden. Dies kann mithilfe der IErrorHandler-Schnittstellen implementiert werden.

  • Benutzerdefiniertes Autorisierungsverhalten Benutzer können eine benutzerdefinierte Zugriffssteuerung implementieren, indem sie die Vertrags- und Vorgangslaufzeitelemente erweitern und auf in der Nachricht enthaltenen Tokens basierende Sicherheitsüberprüfungen hinzufügen. Dies kann entweder mit den Nachrichteninterceptor- oder den Parameterinterceptorschnittstellen erreicht werden. Beispiele finden Sie unter Sicherheitserweiterbarkeit.

    Achtung

    Da das Ändern der Sicherheitseigenschaften potentiell die Sicherheit von WCF-Anwendungen gefährden kann, wird dringend empfohlen, sicherheitsbezogene Änderungen mit Sorgfalt vorzunehmen und vor der Bereitstellung umfassend zu testen.

  • Benutzerdefinierte WCF-Laufzeitvalidierungs-Steuerelemente. Sie können benutzerdefinierte Validierungssteuerelemente installieren, die Dienste, Verträge und Bindungen überprüfen, um Sicherheitsrichtlinien auf Unternehmensebene für WCF-Anwendungen zu erzwingen. (Ein Beispiel finden Sie unter Vorgehensweise: Sperren von Endpunkten im Unternehmen.)

Verwenden der DispatchRuntime-Klasse

Verwenden Sie die DispatchRuntime-Klasse, um entweder das Standardverhalten eines Diensts oder eines einzelnen Endpunkts zu ändern, oder um Objekte einzufügen, die benutzerdefinierte Änderungen für einen oder für beide der folgenden Dienstprozesse implementieren (oder für Clientprozesse im Fall eines Duplexclients):

  • Die Transformation eingehender Nachrichten in Objekte und die Freigabe dieser Objekte als Methodenaufrufe in einem Dienstobjekt.

  • Die Transformation von Objekten, die von der Antwort auf einen Dienstvorgangsaufruf empfangen wurden, in ausgehende Nachrichten.

Die DispatchRuntime-Klasse ermöglicht Ihnen, den Kanal- oder Endpunktverteiler für alle Nachrichten in einem bestimmten Vertrag auch dann abzufangen und zu erweitern, wenn eine Nachricht nicht erkannt wurde. Wenn eine Nachricht eintrifft, die mit keinem im Vertrag deklarierten Vorgang übereinstimmt, wird sie an den Vorgang geleitet, der von der UnhandledDispatchOperation-Eigenschaft zurückgegeben wird. Informationen dazu, wie ein Verteiler erweitert wird, der alle Nachrichten für einen bestimmten Vorgang abfängt, finden Sie unter der DispatchOperation-Klasse.

Es gibt vier Hauptbereiche der Verteilererweiterbarkeit, die von der DispatchRuntime-Klasse verfügbar gemacht werden:

  1. Kanalkomponenten verwenden Eigenschaften der DispatchRuntime-Klasse sowie jene des zugeordneten Kanalverteilers, der von der ChannelDispatcher-Eigenschaft zurückgegeben wird, um festzulegen, wie der Kanalverteiler Kanäle akzeptiert und schließt. Dazu gehören die Eigenschaften ChannelInitializers und InputSessionShutdownHandlers.

  2. Nachrichtenkomponenten werden für jede verarbeitete Nachricht angepasst. Dazu gehören die Eigenschaften MessageInspectors, OperationSelector, Operations und ErrorHandlers.

  3. Instanzkomponenten passen die Erstellung, Lebensdauer und Freigabe von Instanzen des Diensttyps an. Weitere Informationen zur Lebensdauer von Dienstobjekten finden Sie in den Ausführungen zur InstanceContextMode-Eigenschaft. Dazu gehören die Eigenschaften InstanceContextInitializers und InstanceProvider.

  4. Sicherheitsrelevante Komponenten können die folgenden Eigenschaften verwenden:

In der Regel werden benutzerdefinierte Erweiterungsobjekte einer DispatchRuntime-Eigenschaft zugewiesen oder durch ein Dienstverhalten (ein Objekt, das IServiceBehavior implementiert), durch ein Vertragsverhalten (ein Objekt, das IContractBehavior implementiert) oder durch ein Endpunktverhalten (ein Objekt, das IEndpointBehavior implementiert) in eine Auflistung eingefügt. Das installierende Verhaltensobjekt wird dann der entsprechenden Verhaltensauflistung entweder programmgesteuert oder durch Implementierung eines benutzerdefinierten BehaviorExtensionElement-Objekts hinzugefügt, um das Verhalten, das eingefügt werden soll, mithilfe einer Anwendungskonfigurationsdatei zu aktivieren.

Duplexclients (Clients, die den durch einen Duplexdienst angegebenen Rückrufvertrag implementieren) verfügen auch über ein DispatchRuntime-Objekt, auf das mithilfe der CallbackDispatchRuntime-Eigenschaft zugegriffen werden kann.

Verwenden der DispatchOperation-Klasse

Die DispatchOperation-Klasse ist der Speicherort für Laufzeitänderungen und die Einfügemarke für benutzerdefinierte Erweiterungen, die nur auf einen Dienstvorgang abzielen. (Um das Dienstlaufzeit-Verhalten für alle Nachrichten in einem Vertrag zu ändern, verwenden Sie die DispatchRuntime-Klasse.)

Installieren Sie DispatchOperation-Änderungen mithilfe eines benutzerdefinierten Dienstverhaltensobjekts.

Verwenden Sie die Operations-Eigenschaft, um das DispatchOperation-Objekt zu suchen, das einen bestimmten Dienstvorgang darstellt.

Die folgenden Eigenschaften kontrollieren die Laufzeitausführung auf Vorgangsebene:

Siehe auch