Vorgangsformatierer und Vorgangsauswahl

Dieses Beispiel zeigt, wie Windows Communication Foundation (WCF)-Erweiterungspunkte verwendet werden können, um Nachrichtendaten in einem anderen Format als in WCF erwartet zuzulassen. Standardmäßig erwarten WCF-Formatierer, dass Methodenparameter unter dem soap:body-Element enthalten sind. Das Beispiel zeigt, wie ein benutzerdefinierter Vorgangsformatierer implementiert wird, der Parameterdaten aus einer HTTP-GET-Abfragezeichenfolge stattdessen analysiert und mit diesen Daten dann Methoden aufruft.

Das Beispiel basiert auf dem Beispiel 'Erste Schritte', das den ICalculator-Dienstvertrag implementiert. Es zeigt, wie Add-, Subtract-, Multiply- und Divide-Nachrichten so geändert werden können, dass für Client-an-Server-Anforderungen HTTP GET und für Server-zu-Client-Antworten HTTP POST mit POX-Nachrichten verwendet werden.

Zu diesem Zweck enthält das Beispiel Folgendes:

  • QueryStringFormatter, der IClientMessageFormatter und IDispatchMessageFormatter für den Client bzw. den Server implementiert und die Daten in der Abfragezeichenfolge verarbeitet.
  • UriOperationSelector, die IDispatchOperationSelector auf dem Server implementiert, um die Vorgangsverteilung anhand des Vorgangsnamens in der GET-Anforderung zu verteilen.
  • EnableHttpGetRequestsBehavior-Endpunktverhalten (und entsprechende Konfiguration), das die erforderliche Vorgangsauswahl der Laufzeit hinzufügt.
  • Zeigt, wie ein neuer Vorgangsformatierer in die Laufzeit eingefügt wird.
  • In diesem Beispiel sind sowohl der Client als auch der Dienst Konsolenanwendungen (.exe).

Tipp

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.

Grundbegriffe

QueryStringFormatter - Der Vorgangsformatierer ist die Komponente in WCF, die für das Umwandeln einer Nachricht in ein Array von Parameterobjekten und eines Arrays von Parameterobjekten in eine Nachricht verantwortlich ist. Auf dem Client erfolgt dies mithilfe der IClientMessageFormatter-Schnittstelle, und auf dem Server mit der IDispatchMessageFormatter-Schnittstelle. Mit diesen Schnittstellen können Benutzer die Anforderungs- und Antwortnachrichten aus der Serialize-Methode und der Deserialize-Methode abrufen.

In diesem Beispiel implementiert QueryStringFormatter beide Schnittstellen und wird sowohl auf dem Client als auch auf dem Server implementiert.

Anforderung:

  • Das Beispiel verwendet die TypeConverter-Klasse, um Parameterdaten in der Anforderungsnachricht in und aus Zeichenfolgen zu konvertieren. Wenn ein TypeConverter für einen bestimmten Typ nicht verfügbar ist, löst der Beispielformatierer eine Ausnahme aus.
  • In der IClientMessageFormatter.SerializeRequest-Methode auf dem Client erstellt der Formatierer einen URI mit der entsprechenden Empfängeradresse und fügt den Vorgangsnamen als Suffix an. Dieser Name dient dann zum Verteilen zum entsprechenden Vorgang auf dem Server. Dann nimmt er das Array mit Parameterobjekten und serialisiert die Parameterdaten mithilfe von Parameternamen und den von der TypeConverter-Klasse konvertierten Werten in die URI-Abfragezeichenfolge. Die To-Eigenschaft und die Via-Eigenschaft werden dann auf diesen URI festgelegt. Auf MessageProperties wird über die Properties-Eigenschaft zugegriffen.
  • In der IDispatchMessageFormatter.DeserializeRequest-Methode auf dem Server ruft der Formatierer den Via-URI in den Eigenschaften der eingehenden Anforderungsnachricht ab. Er analysiert die Name-Wert-Paare in der URI-Abfragezeichenfolge in Parameternamen und Werte und füllt mit diesen Parameternamen und Werten das an die Methode übergebene Parameterarray auf. Beachten Sie, dass die Vorgangsverteilung bereits stattgefunden hat; daher wird das Namenssuffix in dieser Methode ignoriert.

Antwort:

  • In diesem Beispiel wird HTTP GET nur für die Anforderung verwendet. Der Formatierer delegiert das Senden der Antwort an den ursprünglichen Formatierer, von dem XML-Nachrichten generiert worden wären. Eines der Ziele dieses Beispiels besteht darin, zu zeigen, wie solch ein delegierender Formatierer implementiert werden kann.

UriPathSuffixOperationSelector-Klasse

Mit der IDispatchOperationSelector-Schnittstelle können Benutzer ihre eigene Logik für die Entscheidung implementieren, für welchen Vorgang eine bestimmte Nachricht weitergeleitet werden soll.

In diesem Beispiel muss UriPathSuffixOperationSelector zum Auswählen des entsprechenden Vorgangs auf dem Server implementiert werden, da anstelle eines Aktionsheaders in der Nachricht der Vorgangsname in dem HTTP-GET-URI eingetragen wird. Das Beispiel ist so eingerichtet, dass bei Vorgangsnamen die Groß- und Kleinschreibung nicht beachtet werden muss.

Die SelectOperation-Methode nimmt die eingehende Nachricht entgegen und schlägt den Via-URI in deren Nachrichteneigenschaften nach. Sie extrahiert das Vorgangsnamenssuffix aus dem URI, schlägt in einer internen Tabelle den Namen des Vorgangs nach, an den die Nachricht weitergeleitet werden soll, und gibt diesen Vorgangsnamen dann zurück.

EnableHttpGetRequestsBehavior-Klasse

Die UriPathSuffixOperationSelector-Komponente kann programmgesteuert oder über ein Endpunktverhalten eingerichtet werden. Das Beispiel implementiert das EnableHttpGetRequestsBehavior-Verhalten, das in der Anwendungskonfigurationsdatei des Diensts angegeben wird.

Auf dem Server:

Der OperationSelector wird auf die IDispatchOperationSelector-Implementierung festgelegt.

Standardmäßig verwendet WCF einen Adressfilter mit exakter Übereinstimmung. Der URI in der eingehenden Nachricht enthält ein Vorgangsnamenssuffix, gefolgt von einer Abfragezeichenfolge, die Parameterdaten enthält. Daher ändert das Endpunktverhalten auch den Adressfilter in einen Präfixübereinstimmungsfilter. Zu diesem Zweck verwendet es die WCF PrefixEndpointAddressMessageFilter-Eigenschaft.

Installieren von Vorgangsformatierern

Vorgangsverhaltensweisen, die Formatierer angeben, sind eindeutig. Standardmäßig wird ein solches Verhalten für jeden Vorgang stets zum Erstellen des erforderlichen Vorgangsformatierers implementiert. Auch wenn diese Verhaltensweisen wie noch ein weiteres Vorgangsverhalten aussehen mögen, sind sie nicht durch andere Attribute zu identifizieren. Zum Installieren eines Ersatzverhaltens muss die Implementierung zuerst nach speziellen, vom WCF-Typladeprogramm standardmäßig installierten Formatiererverhalten suchen, und das dann entweder ersetzen oder ein kompatibles Verhalten so hinzufügen, dass es nach dem Standardverhalten ausgeführt wird.

Diese Vorgangsformatiererverhalten können programmgesteuert vor dem Aufruf von System.ServiceModel.Channels.CommunicationObject.Open eingerichtet werden, oder indem man ein Vorgangsverhalten angibt, das nach dem Standardverhalten ausgeführt wird. Es kann jedoch nicht einfach wie ein Endpunktverhalten (und damit per Konfiguration) eingerichtet werden, da das Verhaltensmodell das Ersetzen eines Verhaltens durch ein anderes oder sonstiges Ändern der Beschreibungsstruktur nicht zulässt.

Auf dem Client:

Die IClientMessageFormatter-Implementierung muss implementiert werden, damit sie die Anforderungen in HTTP-GET-Anforderungen konvertieren und für Antworten an den ursprünglichen Formatierer delegieren kann. Dies erfolgt durch Aufrufen der EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior-Hilfsmethode.

Es muss vor dem Aufruf von CreateChannel durchgeführt werden.

    void ReplaceFormatterBehavior(OperationDescription operationDescription, EndpointAddress address)
    {
        // Remove the DataContract behavior if it is present.
        IOperationBehavior formatterBehavior = operationDescription.Behaviors.Remove<DataContractSerializerOperationBehavior>();
        if (formatterBehavior == null)
        {
            // Remove the XmlSerializer behavior if it is present.
            formatterBehavior = operationDescription.Behaviors.Remove<XmlSerializerOperationBehavior>();
            ...
        }

        // Remember what the innerFormatterBehavior was.
        DelegatingFormatterBehavior delegatingFormatterBehavior = new DelegatingFormatterBehavior(address);
        delegatingFormatterBehavior.InnerFormatterBehavior = formatterBehavior;
       operationDescription.Behaviors.Add(delegatingFormatterBehavior);
    }

Auf dem Server:

  • Die IDispatchMessageFormatter-Schnittstelle muss implementiert werden, damit sie HTTP-GET-Anforderungen lesen und zum Schreiben von Antworten an den ursprünglichen Formatierer delegieren kann. Dies erfolgt durch Aufrufen derselben EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior-Hilfsmethode wie beim Client (siehe vorheriges Codebeispiel).
  • Das muss erfolgen, bevor Open aufgerufen wird. In diesem Beispiel wird gezeigt, wie der Formatierer manuell geändert wird, bevor Open aufgerufen wird. Dasselbe lässt sich auch erreichen, indem man eine Klasse von ServiceHost ableitet, die vor dem Öffnen EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior aufruft (Beispiel dazu finden Sie in der Hostingdokumentation).

Benutzerfreundlichkeit

Auf dem Server:

  • Die ICalculator-Serverimplementierung muss nicht geändert werden.

  • Die App.config-Datei für den Dienst muss eine benutzerdefinierte POX-Bindung verwenden, die für das messageVersion-Attribut des textMessageEncoding-Elements None festlegt.

        <bindings>
          <customBinding>
            <binding name="poxBinding">
              <textMessageEncoding messageVersion="None" />
              <httpTransport />
            </binding>
          </customBinding>
        </bindings>
    
  • Außerdem muss die App.config-Datei für den Dienst das benutzerdefinierte EnableHttpGetRequestsBehavior angeben, indem sie es dem Abschnitt mit den Verhaltenserweiterungen hinzufügt und verwendet.

        <behaviors>
          <endpointBehaviors>
            <behavior name="enableHttpGetRequestsBehavior">
              <enableHttpGetRequests />
            </behavior>
          </endpointBehaviors>
        </behaviors>
    
        <extensions>
          <behaviorExtensions>
            <!-- Enabling HTTP GET requests: Behavior Extension -->
            <add 
              name="enableHttpGetRequests"           type="Microsoft.ServiceModel.Samples.EnableHttpGetRequestsBehaviorElement, QueryStringFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </behaviorExtensions>
        </extensions>
    
  • Fügen Sie Vorgangsformatierer vor dem Aufrufen von Open hinzu.

Auf dem Client:

  • Die Clientimplementierung muss nicht geändert werden.

  • Die App.config-Datei für den Client muss eine benutzerdefinierte POX-Bindung verwenden, die für das messageVersion-Attribut des textMessageEncoding-Elements None festlegt. Ein Unterschied zum Dienst besteht darin, dass der Client die manuelle Adressierung aktivieren muss, damit die Empfängeradresse der ausgehenden Nachricht geändert werden kann.

        <bindings>
          <customBinding>
            <binding name="poxBinding">
              <textMessageEncoding messageVersion="None" />
              <httpTransport manualAddressing="True" />
            </binding>
          </customBinding>
        </bindings>
    
  • Die App.config für den Client muss dasselbe benutzerdefinierte EnableHttpGetRequestsBehavior wie der Server angeben.

  • Fügen Sie Vorgangsformatierer vor dem Aufrufen von CreateChannel hinzu.

Wenn Sie das Beispiel ausführen, werden die Anforderungen und Antworten für den Vorgang im Clientkonsolenfenster angezeigt. Alle vier Vorgänge (Add, Subtract, Multiply und Divide) müssen erfolgreich sein.

So richten Sie das Beispiel ein, erstellen es und führen es aus

  1. Stellen Sie sicher, dass Sie Beispiele zum einmaligen Setupverfahren für Windows Communication Foundation ausgeführt haben.

  2. Folgen Sie zum Erstellen der Projektmappe den Anweisungen unter Erstellen der Windows Communication Foundation-Beispiele.

  3. Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder über Computer hinweg ausführen möchten, folgen Sie den Anweisungen unter Durchführen der Windows Communication Foundation-Beispiele.

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.