Benutzerdefinierte Encoder
In diesem Thema wird das Erstellen benutzerdefinierter Encoder behandelt.
In Windows Communication Foundation (WCF) wird mithilfe einer Bindung angegeben, auf welche Weise Daten in einem Netzwerk zwischen Endpunkten übertragen werden sollen. Eine Bindung setzt sich aus einer Reihe von Bindungselementen zusammen. Eine Bindung enthält optionale Protokollbindungselemente, wie Sicherheit, ein erforderliches Nachrichtenencoder-Bindungselement und ein erforderliches Transportbindungselement. Ein Nachrichtenencoder wird von einem Nachrichtencodierungs-Bindungselement dargestellt. WCF verfügt über drei Nachrichtenencoder: einen Binärencoder, einen Transmission Optimization Mechanism (MTOM)-Encoder und einen Textencoder.
Ein Bindungselement für die Nachrichtencodierung dient zum Serialisieren einer ausgehenden Message. Anschließend wird die Nachricht an den Transport übergeben, oder die serialisierte Form einer Nachricht wird vom Transport empfangen und an die Protokollebene übergeben. Ist die Protokollebene nicht vorhanden, erfolgt die Übergabe an die Anwendung.
Message-Instanzen werden von Nachrichtenencodern in und aus Übertragungsdarstellungen transformiert. Obgleich Encoder als Elemente beschrieben werden, die der Transportebene des Kanalstapels übergeordnet sind, befinden sie sich eigentlich auf der Transportebene. Von Transporten (beispielsweise HTTP) wird die Nachricht gemäß den Anforderungen des Transportstandards formatiert. Die Encoder (beispielsweise Text-XML) dienen lediglich zum Codieren der Nachricht.
Beim Herstellen einer Verbindung mit einem vorhandenen Client oder Server muss möglicherweise eine bestimmte Nachrichtencodierung verwendet werden. Sie können jedoch WCF-Dienste über mehrere Endpunkte bereitstellen, von denen jeweils eine andere Nachrichtencodierung verwendet wird. Wenn ein einzelner Encoder nicht für alle Zielbenutzer des Diensts ausreicht, können Sie den Dienst über mehrere Endpunkte hinweg verfügbar machen. Somit kann von Clientanwendungen der optimale Endpunkt gewählt werden. Die Verwendung mehrerer Endpunkte ermöglicht es Ihnen, die Vorteile anderer Nachrichtencodierungen mit anderen Bindungselementen zu kombinieren.
Vom System bereitgestellte Encoder
Von WCF werden mehrere systemeigene Bindungen bereitgestellt, um die häufigsten Anwendungsszenarios abzudecken. In jeder dieser Bindungen wird ein Transport mit einem Nachrichtenencoder und anderen Optionen (beispielsweise Sicherheit) kombiniert. In diesem Thema wird das Erweitern der in integrierten Nachrichtenencoder vom Typ Text
, Binary
, und MTOM
erläutert. Darüber hinaus erhalten Sie Informationen zum Erstellen benutzerdefinierter Encoder. Der Textnachrichtenencoder unterstützt sowohl reine XML-Codierung als auch SOAP-Codierungen. Der reine XML-Codierungsmodus des Textnachrichtenencoders wird als POX-Encoder ("Plain Old XML") bezeichnet, um ihn von der textbasierten SOAP-Codierung zu unterscheiden.
Weitere Informationen zu den Kombinationen von Bindungselementen, die von den vom System bereitgestellten Bindungen bereitgestellt werden, finden Sie im entsprechenden Abschnitt unter Auswählen eines Transports.
Arbeiten mit vom System bereitgestellten Encodern
Das Hinzufügen einer Codierung zu einem Bindungselement erfolgt mithilfe einer von MessageEncodingBindingElement abgeleiteten Klasse.
Von WCF werden die folgenden von der MessageEncodingBindingElement-Klasse abgeleiteten Bindungselementtypen bereitgestellt, mit denen sich Text-, Binär- sowie MTOM-Codierungen verwenden lassen:
TextMessageEncodingBindingElement: Der am wenigsten effiziente Encoder für XML-Nachrichten, der jedoch das höchste Maß an Interoperabilität bietet. Text-XML kann in der Regel von Webdiensten oder Webdienstclients interpretiert werden. Das Übermitteln umfangreicher Blöcke binärer Daten in Textform ist jedoch wenig effizient.
Die BinaryMessageEncodingBindingElement-Klasse stellt das Bindungselement dar, von dem die Zeichencodierung und die für binäre XML-Nachrichten verwendete Nachrichtenversion angegeben werden. Hierbei handelt es sich um die effizienteste Codierungsoption, diese besitzt jedoch gleichzeitig die geringste Interoperabilität, da sie lediglich von WCF-Endpunkten unterstützt wird.
MtomMessageEncodingBindingElement: Stellt das Bindungselement dar, von dem die Zeichencodierung und die für eine Meldung mit MTOM-Codierung (Message Transmission Optimization Mechanism) verwendete Nachrichtenversion angegeben werden. MTOM ist eine effiziente Technologie zum Übertragen von Binärdaten in WCF-Nachrichten. Der MTOM-Encoder versucht, einen Ausgleich zwischen Effizienz und Interoperabilität zu erschaffen. Die MTOM-Verschlüsselung überträgt die meisten XML-Daten in Textform, optimiert aber große Binärdatenblöcke durch Übertragung ohne Textkonvertierung.
Vom Bindungselement wird eine Binär-, MTOM- oder Text-MessageEncoderFactory erstellt. Von der Factory wird eine MessageEncoderFactory-Binär-, MTOM- oder Textinstanz erstellt. Üblicherweise ist lediglich eine einzelne Instanz vorhanden. Bei Verwendung von Sitzungen kann jedoch für jede Sitzung ein anderer Encoder bereitgestellt werden. Vom Binärencoder wird diese Möglichkeit zum Koordinieren dynamischer Wörterbücher genutzt (siehe XML-Infrastruktur).
Die Methoden ReadMessage und WriteMessage bilden den Kern der Encoder. Sie dienen zum Lesen einer Nachricht aus einem Stream oder aus einem Byte-Array. Bytearrays werden verwendet, wenn der Transport im Puffermodus betrieben wird. Nachrichten werden stets in Streams geschrieben. Muss die Nachricht gepuffert werden, wird hierzu ein Stream bereitgestellt.
Die restlichen Member arbeiten mit Supportinhalten, Medientypen und MessageVersion. Die Encodermethoden werden vom Transport aufgerufen, um zu testen, ob die eingehende Nachricht damit decodiert werden kann, oder um festzustellen, ob die ausgehende Nachricht für diesen Encoder geeignet ist.
Mit jeder der drei Encoderimplementierungen werden Eigenschaften hinzugefügt, die für die jeweilige Codierung benötigt werden. Darüber hinaus sind sie vollständig konfigurierbar. Von den Encodern werden überdies Readerkontingente mit sicheren Standardeinstellungen verfügbar gemacht. Informationen zu Kontingenten finden Sie im Thema zur XML-Infrastruktur.
Funktionen der vom System bereitgestellten Encoder
Die vom System bereitgestellten Encoder verfügen über eine Reihe von Funktionen.
Pooling
Für jede der Encoderimplementierungen wird versucht, ein Höchstmaß an Pooling zu erzielen. Eine geeignete Vorgehensweise zum Verbessern der Leistung verwalteten Codes besteht im Verringern der Speicherbelegung. Für das Pooling wird von den Implementierungen die SynchronizedPool
-Klasse verwendet. Die C#-Datei enthält eine Beschreibung der zusätzlichen, von dieser Klasse verwendeten Optimierungen.
Die Instanzen XmlDictionaryReader und XmlDictionaryWriter werden in einem Pool zusammengefasst und neu initialisiert, um eine Neuzuordnung von Instanzen für jede Nachricht zu unterbinden. Bei einem Reader wird dieser mithilfe eines OnClose
-Rückrufs zurückgefordert, wenn Close()
aufgerufen wird. Vom Encoder werden auch einige Nachrichtenzustandsobjekte wiederverwendet, die bei der Nachrichtenerstellung verwendet wurden. Die Größe dieser Pools kann über die Eigenschaften MaxReadPoolSize
und MaxWritePoolSize
für jede der drei von MessageEncodingBindingElement abgeleiteten Klassen konfiguriert werden.
Binärcodierung
Werden bei der Binärcodierung Sitzungen verwendet, muss die dynamische Wörterbuchzeichenfolge an den Empfänger der Nachricht übermittelt werden. Hierzu werden der Nachricht die dynamischen Wörterbuchzeichenfolgen als Präfix hinzugefügt. Vom Empfänger werden die Zeichenfolgen entfernt und der Sitzung hinzugefügt. Anschließend wird die Nachricht verarbeitet. Für die ordnungsgemäße Übergabe der Wörterbuchzeichenfolgen muss der Transport gepuffert werden.
Die Zeichenfolgen werden der Meldung mithilfe einer internen AddSessionInformationToMessage
-Methode angehängt. Mit dieser Methode werden die Zeichenfolgen dem Nachrichtenanfang als UTF-8 hinzugefügt. Davor wird als Präfix die Länge der Zeichenfolgen eingefügt. Der gesamte Wörterbuchheader wird daraufhin mit einem Präfix versehen, das die Datenlänge enthält. Der umgekehrte Vorgang erfolgt mittels einer internen ExtractSessionInformationFromMessage
-Methode.
Zusätzlich zum Verarbeiten dynamischer Wörterbuchschlüssel erfolgt der Empfang sitzungsbasierter Meldungen auf eindeutige Weise. Anstatt einen Reader über das Dokument zu erstellen und dieses anschließend zu verarbeiten, wird der binäre Stream bei der Binärcodierung mithilfe der internen MessagePatterns
-Klasse zerlegt. Diesem Vorgang liegt folgender Gedanke zugrunde: Die meisten Nachrichten besitzen einen bestimmten Satz von Headern, die in einer bestimmten Reihenfolge angezeigt werden, wenn sie von WCF generiert wurden. Die Nachricht wird vom Mustersystem auf Basis der jeweiligen Erwartung zerlegt. Ist der Vorgang erfolgreich, wird ohne XML-Analyse ein MessageHeaders-Objekt erstellt. Andernfalls wird wieder die Standardmethode verwendet.
MTOM-Codierung
Die MtomMessageEncodingBindingElement-Klasse verfügt über eine zusätzliche Konfigurationseigenschaft mit der Bezeichnung MaxBufferSize. Hierdurch wird eine Obergrenze für die Menge der Daten festgelegt, die beim Lesen einer Nachricht gepuffert werden dürfen. Das XML Information Set (Infoset) sowie andere MIME-Teile müssen möglicherweise gepuffert werden, um MIME-Teile wieder zu einer einzelnen Nachricht zusammenzufügen.
Für das ordnungsgemäße Funktionieren mit HTTP werden vom internen MTOM-Nachrichtenencoder einige interne APIs für GetContentType
(ebenfalls intern) und WriteMessage
bereitgestellt. Letzteres Element ist öffentlich und kann außer Kraft gesetzt werden. Damit sichergestellt ist, dass die Werte in den HTTP-Headern mit den Werten in den MIME-Headern übereinstimmen, ist ein höheres Kommunikationsaufkommen erforderlich.
Intern werden vom MTOM-Nachrichtenencoder Textreader von WCF verwendet, und er ist vergleichbar mit dem Textencoder. Der Hauptunterschied besteht darin, dass vom MTOM-Nachrichtenencoder große Binärcodeabschnitte (oder "Binary Large Objects", so genannte BLOBs) optimiert werden, indem sie vor dem Einbetten in die Nachrichtenbytes nicht in eine Base-64-Codierung umgewandelt werden. Stattdessen bleiben diese BLOBs extrahiert und werden als MIME-Anhänge referenziert.
Schreiben eigener Encoder
Zum Implementieren eines eigenen Nachrichtenencoders müssen benutzerdefinierte Implementierungen der folgenden abstrakten Basisklassen bereitgestellt werden:
Die Umwandlung der speicherinternen Version einer Nachricht zu einer Version, die in einen Stream geschrieben werden kann, ist Teil der MessageEncoder-Klasse, die als Factory für XML-Reader und XML-Writer mit Unterstützung für bestimmte XML-Codierungstypen fungiert.
Folgende Schlüsselmethoden dieser Klasse müssen außer Kraft gesetzt werden:
WriteMessage: nimmt ein MessageEncodingBindingElement-Objekt an und schreibt es in ein Stream-Objekt.
ReadMessage: nimmt ein Stream-Objekt sowie eine maximale Headergröße an und gibt ein Message-Objekt zurück.
Die Umwandlung zwischen dem standardmäßigen Transportprotokoll und der benutzerdefinierten Codierung wird anhand des in diese Methoden geschriebenen Codes behandelt.
Der nächste Schritt besteht im Codieren einer Factoryklasse zum Erstellen des benutzerdefinierten Encoders. Überschreiben Sie den Encoder, um eine Instanz des benutzerdefinierten MessageEncoder zurückzugeben.
Verbinden Sie anschließend die benutzerdefinierte MessageEncoderFactory mit dem Bindungselementstapel für die Konfiguration des Diensts oder des Clients durch Überschreiben der CreateMessageEncoderFactory-Methode, um eine Instanz der Factory zurückzugeben.
Es gibt zwei Beispiele mit WCF, die diesen Prozess mit Beispielcode veranschaulichen: Custom Message Encoder: Custom Text Encoder and Custom Message Encoder: Compression Encoder.