Compartilhar via


Escolhendo um padrão de troca de mensagens

A primeira etapa ao escrever um transporte personalizado é decidir quais padrões de troca de mensagens (ou MEPs) são necessários para o canal que você está desenvolvendo. Este tópico descreve as opções disponíveis e discute os vários requisitos. Esta é a primeira tarefa na lista de tarefas de desenvolvimento de canais descrita em Desenvolvendo canais.

Seus padrões de troca de mensagens

Há três MEPs a escolher:

  • Datagrama (IInputChannel e IOutputChannel)

    Ao usar um MEP de datagrama, um cliente envia uma mensagem usando uma troca disparar e esquecer. Uma troca do tipo disparar e esquecer é aquela que requer confirmação de entrega bem-sucedida fora da faixa. A mensagem pode ser perdida em trânsito e nunca chegar ao serviço. Se a operação de envio for concluída com êxito na extremidade do cliente, não haverá garantia de que o ponto de extremidade remoto tenha recebido a mensagem. O datagrama é um bloco de construção fundamental para mensagens, pois você pode criar seus próprios protocolos além dele, incluindo protocolos confiáveis e protocolos seguros. Os canais de datagrama do cliente implementam a interface IOutputChannel e os canais de datagrama de serviço implementam a interface IInputChannel.

  • Solicitação-resposta (IRequestChannel e IReplyChannel)

    Nesse MEP, uma mensagem é enviada e uma resposta é recebida. O padrão consiste em pares de solicitação-resposta. Exemplos de chamadas de solicitação-resposta são chamadas de procedimento remoto (RPC) e solicitações GET do navegador. Esse padrão também é conhecido como meio duplex. Nesse MEP, os canais do cliente implementam IRequestChannel e os canais de serviço implementam IReplyChannel.

  • Duplex (IDuplexChannel)

    O MEP duplex permite que um número arbitrário de mensagens seja enviado por um cliente e recebido em qualquer ordem. O MEP duplex é como uma conversa telefônica, onde cada palavra que está sendo falada é uma mensagem. Como ambos os lados podem enviar e receber nesse MEP, a interface implementada pelos canais de cliente e de serviço é IDuplexChannel.

Flowchart showing the three basic message exchange patterns
Os três padrões básicos de troca de mensagens. De cima para baixo: datagrama, solicitação-resposta e duplex.

Cada um desses MEPs também pode dar suporte a sessões. Uma sessão (e a implementação de System.ServiceModel.Channels.ISessionChannel<TSession> do tipo System.ServiceModel.Channels.ISession) correlaciona todas as mensagens enviadas e recebidas em um canal. O padrão solicitação-resposta é uma sessão autônoma de duas mensagens, pois a solicitação e a resposta estão correlacionadas. Por outro lado, o padrão solicitação-resposta que dá suporte a sessões implica que todos os pares de solicitação/resposta nesse canal estão correlacionados entre si. Isso oferece um total de seis MEPs para escolher:

  • Datagrama

  • Solicitação-resposta

  • Duplex

  • Datagrama com sessões

  • Solicitação-resposta com sessões

  • Duplex com sessões

Observação

Para o transporte UDP, o único MEP com suporte é o datagrama, pois o UDP é inerentemente um protocolo do tipo disparar e esquecer.

Sessões e canais com sessão

No mundo da rede, há protocolos orientados a conexão (por exemplo, TCP) e protocolos sem conexão (por exemplo, UDP). O WCF usa o termo sessão para indicar uma abstração lógica semelhante a uma conexão. Os protocolos WCF com sessão são semelhantes aos protocolos de rede orientados a conexão, e os protocolos WCF sem sessão são semelhantes aos protocolos de rede sem conexão.

No modelo de objeto de canal, cada sessão lógica se manifesta como uma instância de um canal com sessão. Portanto, cada nova sessão criada pelo cliente e aceita no serviço corresponde a um novo canal de sessão em cada lado. O diagrama a seguir mostra, na parte superior, a estrutura de canais sem sessão e, na parte inferior, a estrutura de canais com sessão.

Flowchart showing the structure of sessionless and sessionful channels

Um cliente cria um canal com sessão e envia uma mensagem. No lado do serviço, o ouvinte de canais recebe essa mensagem e detecta que ela pertence a uma nova sessão, então ele cria um canal de sessão e o entrega ao aplicativo (em resposta ao aplicativo que chama AcceptChannel no ouvinte do canal). Em seguida, o aplicativo recebe essa mensagem e todas as mensagens subsequentes enviadas na mesma sessão por meio do mesmo canal de sessão.

Outro cliente (ou o mesmo cliente) cria uma sessão e envia uma mensagem. O ouvinte do canal detecta que essa mensagem está em uma nova sessão e cria um canal com sessão e o processo se repete.

Sem sessões, não há correlação entre canais e sessões. Portanto, um ouvinte de canal cria apenas um canal por meio do qual todas as mensagens recebidas são entregues ao aplicativo. Também não há nenhuma ordenação de mensagens porque não há nenhuma sessão na qual manter a ordem das mensagens. A parte superior do gráfico anterior ilustra uma troca de mensagens sem sessão.

Iniciando e encerrando sessões

As sessões são iniciadas no cliente simplesmente criando um canal com sessão. Elas são iniciadas no serviço quando o serviço recebe uma mensagem que foi enviada em uma nova sessão. Da mesma forma, as sessões são encerradas fechando ou anulando um canal com sessão.

A exceção a isso é IDuplexSessionChannel, que é usado para enviar e receber mensagens em um padrão de comunicação duplex e com sessão. É possível que um lado queira parar de enviar mensagens, mas continuar recebendo mensagens, portanto, ao usar IDuplexSessionChannel, há um mecanismo que permite fechar a sessão de saída indicando que você não enviará mais mensagens, mas manter a sessão de entrada aberta, permitindo que você continue a receber mensagens.

Em geral, as sessões são fechadas no lado de saída e não no lado de entrada. Ou seja, os canais de saída com sessão podem ser fechados, encerrando a sessão corretamente. Fechar um canal de saída com sessão faz com que o canal de entrada com sessão correspondente retorne nulo para o aplicativo que está chamando IInputChannel.Receive no IDuplexSessionChannel.

No entanto, os canais de entrada com sessão não devem ser fechados, a menos que IInputChannel.Receive no IDuplexSessionChannel retorne nulo, indicando que a sessão já está fechada. Se IInputChannel.Receive no IDuplexSessionChannel não tiver retornado nulo, fechar um canal de entrada com sessão poderá gerar uma exceção, porque ele poderá receber mensagens inesperadas durante o fechamento. Se um destinatário quiser encerrar uma sessão antes do remetente, ele deverá chamar Abort no canal de entrada, o que encerra abruptamente a sessão.

Escrevendo canais com sessão

Como autor de canal com sessão, há algumas coisas que seu canal deve fazer para fornecer sessões. No lado do envio, o canal precisa:

  • Para cada novo canal, crie uma sessão e associe-a a uma nova ID de sessão, que é uma cadeia de caracteres exclusiva. Ou obtenha uma nova sessão do canal de sessão abaixo de você na pilha.

  • Para cada mensagem enviada usando esse canal, se o canal criou a sessão (em vez de obtê-la da camada abaixo de você), você precisará associar a mensagem à sessão. Para canais de protocolo, isso normalmente é feito adicionando um cabeçalho SOAP. Para canais de transporte, isso normalmente é feito criando uma conexão de transporte ou adicionando informações de sessão ao protocolo de enquadramento.

  • Para cada mensagem enviada usando esse canal, você precisa fornecer as garantias de entrega mencionadas acima. Se você estiver contando com o canal abaixo para fornecer a sessão, esse canal também fornecerá as garantias de entrega. Se você estiver fornecendo a sessão por conta própria, precisará implementar essas garantias como parte do protocolo. Em geral, se você estiver escrevendo um canal de protocolo que pressupõe o WCF em ambos os lados, poderá exigir o transporte TCP ou o canal de Mensagens Confiáveis e contar com qualquer um deles para fornecer uma sessão.

  • Quando ICommunicationObject.Close for chamado em seu canal, execute o trabalho necessário para fechar a sessão usando o tempo limite especificado ou o padrão. Isso pode ser tão simples quanto chamar Close no canal abaixo de você (se você acabou de obter a sessão dela) ou enviar uma mensagem SOAP especial ou fechar uma conexão de transporte.

  • Quando Abort for chamado em seu canal, encerre a sessão abruptamente sem executar E/S. Isso pode significar não fazer nada ou pode envolver a anulação de uma conexão de rede ou algum outro recurso.

No lado de recebimento, seu canal precisa de:

  • Para cada mensagem de entrada, o ouvinte do canal deve detectar a sessão à qual pertence. Se essa for a primeira mensagem na sessão, o ouvinte do canal deverá criar um novo canal e retorná-lo da chamada para IChannelListener<TChannel>.AcceptChannel. Caso contrário, o ouvinte de canal deve localizar o canal existente que corresponde à sessão e entregar a mensagem por meio desse canal.

  • Se o canal estiver fornecendo a sessão (juntamente com as garantias de entrega necessárias), o lado de recebimento poderá precisar executar algumas ações, como reordenar mensagens ou enviar confirmações.

  • Quando Close for chamado em seu canal, execute o trabalho necessário para fechar a sessão usando o tempo limite especificado ou o padrão. Isso poderá resultar em exceções se o canal receber uma mensagem enquanto aguarda o tempo limite de fechamento expirar. Isso ocorre porque o canal estará no estado Fechando quando receber uma mensagem para que ele seja lançado.

  • Quando Abort for chamado em seu canal, encerre a sessão abruptamente sem executar E/S. Novamente, isso pode significar não fazer nada ou pode envolver a anulação de uma conexão de rede ou algum outro recurso.

Confira também