Freigeben über


Benutzerdefinierter Nachrichten-Encoder: Benutzerdefinierter Text-Encoder

Im Textbeispiel wird veranschaulicht, wie ein benutzerdefinierter Textnachrichten-Encoder mithilfe von Windows Communication Foundation (WCF) implementiert wird.

Die TextMessageEncodingBindingElement von WCF unterstützt nur die UTF-8-, UTF-16- und Big-Endian-Unicode-Codierungen. Der benutzerdefinierte Textnachrichten-Encoder in diesem Beispiel unterstützt alle plattformgestützten Zeichencodierungen, die möglicherweise für die Interoperabilität erforderlich sind. Das Beispiel besteht aus einem Clientkonsolenprogramm (.exe), einer Dienstbibliothek (.dll), die von Internetinformationsdienste (IIS) gehostet wird, und einer Textnachrichten-Encoderbibliothek (.dll). Der Dienst implementiert einen Vertrag, der ein Kommunikationsmuster für die Anforderungsantwort definiert. Der Vertrag wird durch die ICalculator Schnittstelle definiert, die mathematische Operationen (Add, Subtrahieren, Multiplizieren und Dividieren) verfügbar macht. Der Client sendet synchrone Anforderungen an einen bestimmten mathematischen Vorgang und der Dienst antwortet mit dem Ergebnis. Sowohl der Client als auch der Dienst verwenden CustomTextMessageEncoder anstelle der Standardeinstellung TextMessageEncodingBindingElement.

Die Implementierung des benutzerdefinierten Codierers besteht aus einer Nachrichten-Codierer-Fabrik, einem Nachrichten-Codierer, einem Nachrichten-Codierungsbindungselement und einem Konfigurationshandler und veranschaulicht Folgendes:

  • Das Erstellen eines benutzerdefinierten Encoders und einer Encoder-Factory.

  • Erstellen eines Bindungselements für einen benutzerdefinierten Encoder.

  • Verwenden der benutzerdefinierten Bindungskonfiguration für die Integration von benutzerdefinierten Bindungselementen.

  • Entwickeln eines benutzerdefinierten Konfigurationshandlers zum Zulassen der Dateikonfiguration eines benutzerdefinierten Bindungselements.

So können Sie das Beispiel einrichten, erstellen und ausführen

  1. Installieren Sie ASP.NET 4.0 mit dem folgenden Befehl.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Stellen Sie sicher, dass Sie das One-Time Setup-Verfahren für die Windows Communication Foundation-Beispieleausgeführt haben.

  3. Befolgen Sie zum Erstellen der Projektmappe die Anweisungen unter Erstellen der Windows Communication Foundation-Beispiele.

  4. 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.

Nachrichtenencoder-Factory und der Nachrichtenencoder

Wenn der ServiceHost oder der Clientkanal geöffnet wird, erstellt die Entwurfszeit-Komponente CustomTextMessageBindingElement die CustomTextMessageEncoderFactory. Die Factory erstellt den CustomTextMessageEncoder. Der Nachrichten-Encoder arbeitet sowohl im Streamingmodus als auch im pufferten Modus. Sie verwendet XmlReader zum Lesen und XmlWriter zum Schreiben der Nachrichten. Im Gegensatz zu den optimierten XML-Lesern und Autoren von WCF, die nur UTF-8, UTF-16 und Big-Endian Unicode unterstützen, unterstützen diese Leser und Autoren die gesamte plattformgestützte Codierung.

Das folgende Codebeispiel zeigt den CustomTextMessageEncoder.

public class CustomTextMessageEncoder : MessageEncoder
{
    private CustomTextMessageEncoderFactory factory;
    private XmlWriterSettings writerSettings;
    private string contentType;

    public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
    {
        this.factory = factory;

        this.writerSettings = new XmlWriterSettings();
        this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
        this.contentType = $"{this.factory.MediaType}; charset={this.writerSettings.Encoding.HeaderName}";
    }

    public override string ContentType
    {
        get
        {
            return this.contentType;
        }
    }

    public override string MediaType
    {
        get
        {
            return factory.MediaType;
        }
    }

    public override MessageVersion MessageVersion
    {
        get
        {
            return this.factory.MessageVersion;
        }
    }

    public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
    {
        byte[] msgContents = new byte[buffer.Count];
        Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
        bufferManager.ReturnBuffer(buffer.Array);

        MemoryStream stream = new MemoryStream(msgContents);
        return ReadMessage(stream, int.MaxValue);
    }

    public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
    {
        XmlReader reader = XmlReader.Create(stream);
        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
    }

    public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
    {
        MemoryStream stream = new MemoryStream();
        XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
        message.WriteMessage(writer);
        writer.Close();

        byte[] messageBytes = stream.GetBuffer();
        int messageLength = (int)stream.Position;
        stream.Close();

        int totalLength = messageLength + messageOffset;
        byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
        Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);

        ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
        return byteArray;
    }

    public override void WriteMessage(Message message, Stream stream)
    {
        XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
        message.WriteMessage(writer);
        writer.Close();
    }
}

Das folgende Codebeispiel zeigt, wie die Nachrichten-Encoder-Factory erstellt wird.

public class CustomTextMessageEncoderFactory : MessageEncoderFactory
{
    private MessageEncoder encoder;
    private MessageVersion version;
    private string mediaType;
    private string charSet;

    internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
        MessageVersion version)
    {
        this.version = version;
        this.mediaType = mediaType;
        this.charSet = charSet;
        this.encoder = new CustomTextMessageEncoder(this);
    }

    public override MessageEncoder Encoder
    {
        get
        {
            return this.encoder;
        }
    }

    public override MessageVersion MessageVersion
    {
        get
        {
            return this.version;
        }
    }

    internal string MediaType
    {
        get
        {
            return this.mediaType;
        }
    }

    internal string CharSet
    {
        get
        {
            return this.charSet;
        }
    }
}

Nachrichtencodierungs-Bindungselement

Die Bindungselemente ermöglichen die Konfiguration des WCF-Laufzeitstapels. Um den benutzerdefinierten Nachrichten-Encoder in einer WCF-Anwendung zu verwenden, ist ein Bindungselement erforderlich, das die Nachrichten-Encoder-Factory mit den entsprechenden Einstellungen auf der entsprechenden Ebene im Laufzeitstapel erstellt.

Die CustomTextMessageBindingElement ist von der BindingElement Basisklasse abgeleitet und erbt von der MessageEncodingBindingElement Klasse. Dadurch können andere WCF-Komponenten dieses Bindungselement als Nachrichtencodierungsbindungselement erkennen. Die Implementierung von CreateMessageEncoderFactory gibt eine Instanz der entsprechenden Nachrichtenencoder-Factory mit entsprechenden Einstellungen zurück.

Die CustomTextMessageBindingElement stellt Einstellungen für MessageVersion, ContentType und Encoding über Eigenschaften zur Verfügung. Der Encoder unterstützt die Versionen Soap11Addressing und Soap12Addressing1. Der Standardwert ist Soap11Addressing1. Der Standardwert ist ContentType "text/xml". Mit Encoding der Eigenschaft können Sie den Wert der gewünschten Zeichencodierung festlegen. Der Beispielclient und -dienst verwendet die ISO-8859-1 -Zeichencodierung (Lateinisch1), die von wcf TextMessageEncodingBindingElement nicht unterstützt wird.

Der folgende Code zeigt, wie Sie die Bindung programmgesteuert mithilfe des benutzerdefinierten Textnachrichten-Encoders erstellen.

ICollection<BindingElement> bindingElements = new List<BindingElement>();
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
CustomTextMessageBindingElement textBindingElement = new CustomTextMessageBindingElement();
bindingElements.Add(textBindingElement);
bindingElements.Add(httpBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);

Hinzufügen von Metadaten-Unterstützung zum Nachrichtencodierungs-Bindungselement

Jeder Typ, der von MessageEncodingBindingElement abgeleitet ist, ist dafür verantwortlich, die Version der SOAP-Bindung im WSDL-Dokument zu aktualisieren, welches für den Dienst generiert wurde. Indem die ExportEndpoint Methode auf der IWsdlExportExtension Schnittstelle implementiert wird und anschließend die erzeugte WSDL entsprechend geändert wird. In diesem Beispiel verwendet die CustomTextMessageBindingElement WSDL-Exportlogik aus der TextMessageEncodingBindingElement.

Für dieses Beispiel wird die Clientkonfiguration handkonfiguriert. Sie können Svcutil.exe nicht verwenden, um die Clientkonfiguration zu generieren, da die Richtlinienbehauptung von CustomTextMessageBindingElement nicht exportiert wird, um sein Verhalten zu beschreiben. In der Regel sollten Sie die IPolicyExportExtension Schnittstelle für ein benutzerdefiniertes Bindungselement implementieren, um eine benutzerdefinierte Richtlinien assertion zu exportieren, die das verhalten oder die Funktion beschreibt, das vom Bindungselement implementiert wird. Für ein Beispiel, wie man eine Richtlinien-Assertion für ein benutzerdefiniertes Bindungselement exportiert, siehe das Beispiel 'Transport: UDP'.

Bindungskonfigurationshandler zur Nachrichtencodierung

Im vorherigen Abschnitt wird gezeigt, wie Sie den benutzerdefinierten Textnachrichten-Encoder programmgesteuert verwenden. CustomTextMessageEncodingBindingSection implementiert einen Konfigurationshandler, der es Ihnen ermöglicht, die Verwendung eines benutzerdefinierten Textnachrichtenencoders innerhalb einer Konfigurationsdatei festzulegen. Die CustomTextMessageEncodingBindingSection Klasse wird von der BindingElementExtensionElement Klasse abgeleitet. Die BindingElementType Eigenschaft informiert das Konfigurationssystem über den Typ des Bindungselements, das für diesen Abschnitt erstellt werden soll.

Alle von CustomTextMessageBindingElement definierten Einstellungen sind als Eigenschaften im CustomTextMessageEncodingBindingSection zugänglich. Die ConfigurationPropertyAttribute hilft dabei, die Attribute der Konfigurationselemente den Eigenschaften zuzuordnen und Standardwerte festzulegen, falls das Attribut nicht festgelegt ist. Nachdem die Werte aus der Konfiguration geladen und auf die Eigenschaften des Typs angewendet wurden, wird die CreateBindingElement Methode aufgerufen, die die Eigenschaften in eine konkrete Instanz eines Bindungselements konvertiert.

Dieser Konfigurationshandler ordnet die folgende Darstellung in der App.config oder Web.config für den Dienst oder Client zu.

<customTextMessageEncoding encoding="utf-8" contentType="text/xml" messageVersion="Soap11Addressing1" />

Im Beispiel wird die ISO-8859-1-Codierung verwendet.

Um diesen Konfigurationshandler zu verwenden, muss er mithilfe des folgenden Konfigurationselements registriert werden.

<extensions>
    <bindingElementExtensions>
        <add name="customTextMessageEncoding" type="
Microsoft.ServiceModel.Samples.CustomTextMessageEncodingBindingSection,
                  CustomTextMessageEncoder" />
    </bindingElementExtensions>
</extensions>