Partilhar via


Transporte: Interoperabilidade WSE 3.0 TCP

O exemplo de transporte de interoperabilidade TCP WSE 3.0 demonstra como implementar uma sessão duplex TCP como um transporte personalizado do Windows Communication Foundation (WCF). Ele também demonstra como você pode usar a extensibilidade da camada de canal para fazer interface através do fio com sistemas implantados existentes. As etapas a seguir mostram como criar esse transporte WCF personalizado:

  1. Começando com um soquete TCP, crie implementações de cliente e servidor que usam o DIME Framing para delinear os limites da IDuplexSessionChannel mensagem.

  2. Crie uma fábrica de canais que se conecta a um serviço TCP WSE e envia mensagens enquadradas pelo cliente IDuplexSessionChannels.

  3. Crie um ouvinte de canal para aceitar conexões TCP de entrada e produzir canais correspondentes.

  4. Certifique-se de que todas as exceções específicas da rede sejam normalizadas para a classe derivada apropriada de CommunicationException.

  5. Adicione um elemento binding que adiciona o transporte personalizado a uma pilha de canais. Para obter mais informações, consulte [Adicionando um elemento de vinculação].

Criando IDuplexSessionChannel

O primeiro passo para escrever o Transporte de Interoperabilidade TCP WSE 3.0 é criar uma implementação de IDuplexSessionChannel on up of a Socket. WseTcpDuplexSessionChannel deriva de ChannelBase. A lógica de enviar uma mensagem consiste em duas partes principais: (1) codificar a mensagem em bytes e (2) enquadrar esses bytes e enviá-los no fio.

ArraySegment<byte> encodedBytes = EncodeMessage(message);

WriteData(encodedBytes);

Além disso, um bloqueio é feito para que as chamadas Send() preservem a garantia de ordem IDuplexSessionChannel e para que as chamadas para o soquete subjacente sejam sincronizadas corretamente.

WseTcpDuplexSessionChannel usa a MessageEncoder para traduzir um Message para e de byte[]. Por ser um transporte, WseTcpDuplexSessionChannel também é responsável por aplicar o endereço remoto com o qual o canal foi configurado. EncodeMessage encapsula a lógica para essa conversão.

this.RemoteAddress.ApplyTo(message);

return encoder.WriteMessage(message, maxBufferSize, bufferManager);

Uma vez que o é codificado Message em bytes, ele deve ser transmitido no fio. Isso requer um sistema para definir os limites da mensagem. O WSE 3.0 usa uma versão do DIME como seu protocolo de enquadramento. WriteData encapsula a lógica de enquadramento para encapsular um byte[] em um conjunto de registros DIME.

A lógica para receber mensagens é semelhante. A principal complexidade é lidar com o fato de que uma leitura de soquete pode retornar menos bytes do que foram solicitados. Para receber uma mensagem, WseTcpDuplexSessionChannel lê bytes fora do fio, decodifica o enquadramento DIME e, em seguida, usa o MessageEncoder para transformar o byte[] em um Message.

A base WseTcpDuplexSessionChannel assume que recebe um soquete conectado. A classe base lida com o desligamento do soquete. Existem três locais que fazem interface com o fechamento do soquete:

  • OnAbort -- feche o soquete desgraciosamente (fechamento rígido).

  • On[Begin]Close -- feche o soquete normalmente (soft close).

  • sessão. CloseOutputSession -- encerre o fluxo de dados de saída (meio fechamento).

Fábrica do Canal

A próxima etapa ao escrever o transporte TCP é criar uma implementação de para canais de IChannelFactory cliente.

  • WseTcpChannelFactory deriva de ChannelFactoryBase<IDuplexSessionChannel>. É uma fábrica que se sobrepõe para produzir canais de OnCreateChannel clientes.

protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)

{

return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);

}

  • ClientWseTcpDuplexSessionChannel adiciona lógica à base WseTcpDuplexSessionChannel para se conectar a um servidor TCP no channel.Open momento. Primeiro, o nome do host é resolvido para um endereço IP, conforme mostrado no código a seguir.

hostEntry = Dns.GetHostEntry(Via.Host);

  • Em seguida, o nome do host é conectado ao primeiro endereço IP disponível em um loop, conforme mostrado no código a seguir.

IPAddress address = hostEntry.AddressList[i];

socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(new IPEndPoint(address, port));

  • Como parte do contrato de canal, todas as exceções específicas do domínio são encapsuladas, como SocketException em CommunicationException.

Ouvinte do canal

A próxima etapa ao escrever o transporte TCP é criar uma implementação de para aceitar canais de IChannelListener servidor.

  • WseTcpChannelListener deriva de ChannelListenerBase<IDuplexSessionChannel> e substitui On[Begin]Open e On[Begin]Close para controlar o tempo de vida de seu soquete de escuta. No OnOpen, um soquete é criado para ouvir em IP_ANY. Implementações mais avançadas podem criar um segundo soquete para ouvir no IPv6 também. Eles também podem permitir que o endereço IP seja especificado no nome do host.

IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, uri.Port);

this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

this.listenSocket.Bind(localEndpoint);

this.listenSocket.Listen(10);

Quando um novo soquete é aceito, um canal de servidor é inicializado com esse soquete. Toda a entrada e saída já está implementada na classe base, por isso este canal é responsável por inicializar o socket.

Adicionando um elemento de vinculação

Agora que as fábricas e os canais são construídos, eles devem ser expostos ao tempo de execução do ServiceModel por meio de uma ligação. Uma associação é uma coleção de elementos de ligação que representa a pilha de comunicação associada a um endereço de serviço. Cada elemento na pilha é representado por um elemento de ligação.

Na amostra, o elemento de ligação é WseTcpTransportBindingElement, que deriva de TransportBindingElement. Ele suporta IDuplexSessionChannel e substitui os seguintes métodos para construir as fábricas associadas à nossa vinculação.

public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)

{

return (IChannelFactory<TChannel>)(object)new WseTcpChannelFactory(this, context);

}

public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)

{

return (IChannelListener<TChannel>)(object)new WseTcpChannelListener(this, context);

}

Ele também contém membros para clonar e retornar nosso BindingElement esquema (wse.tcp).

O console de teste TCP do WSE

O código de teste para usar esse transporte de exemplo está disponível em TestCode.cs. As instruções a seguir mostram como configurar o exemplo WSE TcpSyncStockService .

O código de teste cria uma ligação personalizada que usa MTOM como a codificação e WseTcpTransport como o transporte. Ele também configura o AddressingVersion para estar em conformidade com o WSE 3.0, conforme mostrado no código a seguir.

CustomBinding binding = new CustomBinding();

MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();

mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;

binding.Elements.Add(mtomBindingElement);

binding.Elements.Add(new WseTcpTransportBindingElement());

Ele consiste em dois testes — um teste configura um cliente tipado usando o código gerado a partir do WSDL do WSE 3.0. O segundo teste usa o WCF como cliente e servidor, enviando mensagens diretamente sobre as APIs do canal.

Ao executar o exemplo, a saída a seguir é esperada.

Cliente:

Calling soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Symbol: FABRIKAM
        Name: Fabrikam, Inc.
        Last Price: 120

Symbol: CONTOSO
        Name: Contoso Corp.
        Last Price: 50.07
Press enter.

Received Action: http://SayHello
Received Body: to you.
Hello to you.
Press enter.

Received Action: http://NotHello
Received Body: to me.
Press enter.

Servidor:

Listening for messages at soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Press any key to exit when done...

Request received.
Symbols:
        FABRIKAM
        CONTOSO

Configurar, compilar e executar o exemplo

  1. Para executar este exemplo, você deve ter Web Services Enhancements (WSE) 3.0 para Microsoft .NET e o exemplo WSE TcpSyncStockService instalado.

Nota

Como o WSE 3.0 não é suportado no Windows Server 2008, não é possível instalar ou executar o TcpSyncStockService exemplo nesse sistema operacional.

  1. Depois de instalar o exemplo, faça o TcpSyncStockService seguinte:

    1. Abra o TcpSyncStockService no Visual Studio. (O O exemplo TcpSyncStockService é instalado com o WSE 3.0. Não faz parte do código deste exemplo.)

    2. Defina o projeto StockService como o projeto inicial.

    3. Abra StockService.cs no projeto StockService e comente o atributo [Policy] na StockService classe. Isso desativa a segurança da amostra. Embora o WCF possa interoperar com pontos de extremidade seguros do WSE 3.0, a segurança é desabilitada para manter este exemplo focado no transporte TCP personalizado.

    4. pressione F5 para iniciar o TcpSyncStockServicearquivo . O serviço é iniciado em uma nova janela do console.

    5. Abra este exemplo de transporte TCP no Visual Studio.

    6. Atualize a variável "hostname" no TestCode.cs para corresponder ao nome da máquina que executa o TcpSyncStockService.

    7. pressione F5 para iniciar o exemplo de transporte TCP.

    8. O cliente de teste de transporte TCP é iniciado em um novo console. O cliente solicita cotações de ações do serviço e, em seguida, exibe os resultados em sua janela de console.