Codificador de mensagem personalizado: Codificador de texto personalizado

O exemplo de texto demonstra como implementar um codificador de mensagem de texto personalizado usando o Windows Communication Foundation (WCF).

O TextMessageEncodingBindingElement WCF suporta apenas as codificações Unicode UTF-8, UTF-16 e big-endian. O codificador de mensagem de texto personalizado neste exemplo suporta todas as codificações de caracteres suportadas pela plataforma que podem ser necessárias para a interoperabilidade. O exemplo consiste em um programa de console cliente (.exe), uma biblioteca de serviços (.dll) hospedada pelo IIS (Serviços de Informações da Internet) e uma biblioteca de codificador de mensagens de texto (.dll). O serviço implementa um contrato que define um padrão de comunicação solicitação-resposta. O contrato é definido pela ICalculator interface, que expõe operações matemáticas (Adicionar, Subtrair, Multiplicar e Dividir). O cliente faz solicitações síncronas para uma determinada operação matemática e o serviço responde com o resultado. O cliente e o serviço usam o CustomTextMessageEncoder em vez do padrão TextMessageEncodingBindingElement.

A implementação do codificador personalizado consiste em uma fábrica de codificador de mensagens, um codificador de mensagens, um elemento de vinculação de codificação de mensagens e um manipulador de configuração e demonstra o seguinte:

  • Criação de uma fábrica de codificadores e codificadores personalizados.

  • Criação de um elemento de vinculação para um codificador personalizado.

  • Usando a configuração de vinculação personalizada para integrar elementos de vinculação personalizados.

  • Desenvolvendo um manipulador de configuração personalizado para permitir a configuração de arquivo de um elemento de vinculação personalizado.

Para configurar, compilar e executar o exemplo

  1. Instale o ASP.NET 4.0 usando o seguinte comando.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  3. Para criar a solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

  4. Para executar o exemplo em uma configuração de máquina única ou cruzada, siga as instruções em Executando os exemplos do Windows Communication Foundation.

Fábrica do codificador de mensagens e o codificador de mensagens

Quando o canal ou ServiceHost o cliente é aberto, o componente de tempo de design cria o CustomTextMessageEncoderFactory.CustomTextMessageBindingElement A fábrica cria o CustomTextMessageEncoder. O codificador de mensagens opera no modo de streaming e no modo de buffer. Ele usa o XmlReader e XmlWriter para ler e escrever as mensagens, respectivamente. Ao contrário dos leitores e gravadores XML otimizados do WCF que suportam apenas UTF-8, UTF-16 e Unicode big-endian, esses leitores e gravadores suportam todas as codificações suportadas pela plataforma.

O exemplo de código a seguir mostra o 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();
    }
}

O exemplo de código a seguir mostra como criar a fábrica do codificador de mensagens.

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

Elemento de vinculação de codificação de mensagem

Os elementos de ligação permitem a configuração da pilha de tempo de execução do WCF. Para usar o codificador de mensagens personalizado em um aplicativo WCF, é necessário um elemento binding que crie a fábrica do codificador de mensagens com as configurações apropriadas no nível apropriado na pilha de tempo de execução.

O CustomTextMessageBindingElement deriva da BindingElement classe base e herda da MessageEncodingBindingElement classe. Isso permite que outros componentes do WCF reconheçam esse elemento de vinculação como sendo um elemento de vinculação de codificação de mensagem. A implementação de retorna uma instância da fábrica do codificador de CreateMessageEncoderFactory mensagens correspondente com as configurações apropriadas.

O CustomTextMessageBindingElement expõe as configurações para MessageVersion, ContentTypee Encoding através das propriedades. O codificador suporta as versões Soap11Addressing e Soap12Addressing1. O padrão é Soap11Addressing1. O valor padrão do ContentType é "text/xml". A Encoding propriedade permite que você defina o valor da codificação de caracteres desejada. O cliente e serviço de exemplo usa a codificação de caracteres ISO-8859-1 (Latin1), que não é suportada TextMessageEncodingBindingElement pelo WCF.

O código a seguir mostra como criar programaticamente a associação usando o codificador de mensagem de texto personalizado.

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

Adicionando suporte a metadados ao elemento de vinculação de codificação de mensagens

Qualquer tipo derivado é MessageEncodingBindingElement responsável por atualizar a versão da ligação SOAP no documento WSDL gerado para o serviço. Isso é feito implementando o ExportEndpoint método na interface e, em IWsdlExportExtension seguida, modificando o WSDL gerado. Neste exemplo, o CustomTextMessageBindingElement usa a lógica de exportação WSDL do TextMessageEncodingBindingElement.

Para este exemplo, a configuração do cliente é configurada manualmente. Não é possível usar Svcutil.exe para gerar a configuração do cliente porque o não exporta CustomTextMessageBindingElement uma declaração de política para descrever seu comportamento. Geralmente, você deve implementar a IPolicyExportExtension interface em um elemento de vinculação personalizado para exportar uma declaração de política personalizada que descreva o comportamento ou a capacidade implementada pelo elemento de vinculação. Para obter um exemplo de como exportar uma declaração de política para um elemento de vinculação personalizado, consulte o Transporte: Exemplo de UDP .

Manipulador de configuração de vinculação de codificação de mensagens

A seção anterior mostra como usar o codificador de mensagem de texto personalizado programaticamente. O CustomTextMessageEncodingBindingSection implementa um manipulador de configuração que permite especificar o uso de um codificador de mensagem de texto personalizado dentro de um arquivo de configuração. A CustomTextMessageEncodingBindingSection classe deriva da BindingElementExtensionElement classe. A BindingElementType propriedade informa o sistema de configuração do tipo de elemento de vinculação a ser criado para esta seção.

Todas as configurações definidas por CustomTextMessageBindingElement são expostas como as propriedades no CustomTextMessageEncodingBindingSection. O ConfigurationPropertyAttribute auxilia no mapeamento dos atributos do elemento de configuração para as propriedades e na definição de valores padrão se o atributo não estiver definido. Depois que os valores da configuração são carregados e aplicados às propriedades do tipo, o CreateBindingElement método é chamado, que converte as propriedades em uma instância concreta de um elemento de ligação.

Este manipulador de configuração mapeia para a seguinte representação no App.config ou Web.config para o serviço ou cliente.

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

O exemplo usa a codificação ISO-8859-1.

Para usar esse manipulador de configuração, ele deve ser registrado usando o seguinte elemento de configuração.

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