Udostępnij za pośrednictwem


Niestandardowy koder komunikatów: Niestandardowy koder tekstu

W przykładzie Text pokazano, jak zaimplementować niestandardowy koder komunikatów tekstowych przy użyciu programu Windows Communication Foundation (WCF).

Program TextMessageEncodingBindingElement WCF obsługuje tylko kodowanie UTF-8, UTF-16 i big-endian Unicode. Niestandardowy koder komunikatów tekstowych w tym przykładzie obsługuje wszystkie kodowania znaków obsługiwane przez platformę, które mogą być wymagane do współdziałania. Przykład składa się z programu konsolowego klienta (.exe), biblioteki usług (.dll) hostowanej przez usługi Internet Information Services (IIS) oraz biblioteki kodera komunikatów tekstowych (.dll). Usługa implementuje kontrakt, który definiuje wzorzec komunikacji typu żądanie-odpowiedź. Kontrakt jest definiowany przez ICalculator interfejs, który uwidacznia operacje matematyczne (Dodawanie, Odejmowanie, Mnożenie i Dzielenie). Klient wysyła synchroniczne żądania do danej operacji matematycznej, a usługa odpowiada z wynikiem. Zarówno klient, jak CustomTextMessageEncoder i usługa używają wartości zamiast domyślnej TextMessageEncodingBindingElement.

Implementacja kodera niestandardowego składa się z fabryki kodera komunikatów, kodera komunikatów, elementu powiązania kodowania komunikatów i procedury obsługi konfiguracji oraz demonstruje następujące kwestie:

  • Tworzenie niestandardowego kodera i fabryki kodera.

  • Tworzenie elementu powiązania dla kodera niestandardowego.

  • Używanie niestandardowej konfiguracji powiązania do integrowania niestandardowych elementów powiązania.

  • Tworzenie niestandardowej procedury obsługi konfiguracji w celu umożliwienia konfiguracji pliku niestandardowego elementu powiązania.

Aby skonfigurować, skompilować i uruchomić przykład

  1. Zainstaluj ASP.NET 4.0 przy użyciu następującego polecenia.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  3. Aby skompilować rozwiązanie, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  4. Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.

Fabryka kodera komunikatów i koder komunikatów

Po otwarciu ServiceHost kanału klienta lub składnik CustomTextMessageBindingElement czasu projektowania tworzy element CustomTextMessageEncoderFactory. Fabryka tworzy obiekt CustomTextMessageEncoder. Koder komunikatów działa zarówno w trybie przesyłania strumieniowego, jak i w trybie buforowania. Używa odpowiednio poleceń XmlReader i XmlWriter do odczytywania i zapisywania komunikatów. W przeciwieństwie do zoptymalizowanych czytników XML i składników zapisywania WCF, które obsługują tylko kodowanie UTF-8, UTF-16 i big-endian Unicode, te czytniki i autorzy obsługują wszystkie kodowanie obsługiwane przez platformę.

Poniższy przykład kodu przedstawia element 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();
    }
}

Poniższy przykład kodu pokazuje, jak utworzyć fabrykę kodera komunikatów.

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;
        }
    }
}

Element powiązania kodowania komunikatów

Elementy powiązania umożliwiają konfigurację stosu czasu wykonywania WCF. Aby użyć niestandardowego kodera komunikatów w aplikacji WCF, wymagany jest element powiązania, który tworzy fabrykę kodera komunikatów z odpowiednimi ustawieniami na odpowiednim poziomie w stosie czasu wykonywania.

Element CustomTextMessageBindingElement pochodzi z klasy bazowej BindingElement i dziedziczy z MessageEncodingBindingElement klasy . Dzięki temu inne składniki programu WCF mogą rozpoznawać ten element powiązania jako element powiązania kodowania komunikatów. Implementacja zwraca wystąpienie zgodnej fabryki kodera komunikatów CreateMessageEncoderFactory z odpowiednimi ustawieniami.

Ustawienia CustomTextMessageBindingElement uwidacznia dla MessageVersionwłaściwości , ContentTypei Encoding za pośrednictwem. Koder obsługuje wersje Soap11Addressing i Soap12Addressing1. Wartość domyślna to Soap11Addressing1. Wartość domyślna to ContentType "text/xml". Właściwość Encoding umożliwia ustawienie wartości żądanego kodowania znaków. Przykładowy klient i usługa używają kodowania znaków ISO-8859-1 (Latin1), które nie jest obsługiwane przez TextMessageEncodingBindingElement program WCF.

Poniższy kod pokazuje, jak programowo utworzyć powiązanie przy użyciu niestandardowego kodera komunikatów tekstowych.

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);

Dodawanie obsługi metadanych do elementu powiązania kodowania komunikatów

Każdy typ pochodzący z MessageEncodingBindingElement programu jest odpowiedzialny za aktualizowanie wersji powiązania protokołu SOAP w dokumencie WSDL wygenerowanym dla usługi. Jest to realizowane przez zaimplementowanie ExportEndpoint metody w interfejsie IWsdlExportExtension , a następnie zmodyfikowanie wygenerowanego pliku WSDL. W tym przykładzie użyto CustomTextMessageBindingElement logiki eksportu WSDL z pliku TextMessageEncodingBindingElement.

W tym przykładzie konfiguracja klienta jest ręcznie skonfigurowana. Nie można użyć Svcutil.exe do wygenerowania konfiguracji klienta, ponieważ CustomTextMessageBindingElement nie eksportuje asercji zasad w celu opisania jego zachowania. Interfejs należy zazwyczaj zaimplementować IPolicyExportExtension w niestandardowym elemecie powiązania w celu wyeksportowania niestandardowej asercji zasad opisujących zachowanie lub możliwość zaimplementowaną przez element powiązania. Przykład eksportowania asercji zasad dla niestandardowego elementu powiązania można znaleźć w przykładzie Transport: UDP .

Procedura obsługi konfiguracji powiązania kodowania komunikatów

W poprzedniej sekcji pokazano, jak programowo używać niestandardowego kodera komunikatów tekstowych. Implementuje CustomTextMessageEncodingBindingSection procedurę obsługi konfiguracji, która umożliwia określenie użycia niestandardowego kodera komunikatów tekstowych w pliku konfiguracji. Klasa CustomTextMessageEncodingBindingSection pochodzi z BindingElementExtensionElement klasy . Właściwość BindingElementType informuje system konfiguracji o typie elementu powiązania, który ma zostać utworzony dla tej sekcji.

Wszystkie ustawienia zdefiniowane przez CustomTextMessageBindingElement program są uwidocznione jako właściwości w obiekcie CustomTextMessageEncodingBindingSection. Pomoc ConfigurationPropertyAttribute w mapowaniu atrybutów elementu konfiguracji na właściwości i ustawiania wartości domyślnych, jeśli atrybut nie jest ustawiony. Po załadowaniu i zastosowaniu wartości z konfiguracji do właściwości typu CreateBindingElement wywoływana jest metoda, która konwertuje właściwości na konkretne wystąpienie elementu powiązania.

Ta procedura obsługi konfiguracji mapuje następującą reprezentację w pliku App.config lub Web.config dla usługi lub klienta.

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

W przykładzie użyto kodowania ISO-8859-1.

Aby użyć tej procedury obsługi konfiguracji, należy ją zarejestrować przy użyciu następującego elementu konfiguracji.

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