Compartilhar via


HttpCookieSession

O exemplo HttpCookieSession demonstra como criar um canal de protocolo personalizado para usar cookies HTTP para gerenciamento de sessão. Esse canal permite a comunicação entre os serviços WCF (Windows Communication Foundation) e os clientes do ASMX ou entre os clientes do WCF e os serviços do ASMX.

Quando um cliente chama um método Web em um serviço Web do ASMX baseado em sessões, o mecanismo do ASP.NET faz o seguinte:

  • Gera uma ID exclusiva (ID da sessão).

  • Gera e associa o objeto da sessão à ID exclusiva.

  • Adiciona a ID exclusiva a um cabeçalho de resposta HTTP Set-Cookie e envia ao cliente.

  • Identifica o cliente nas chamadas subsequentes com base na ID da sessão enviada a ele.

O cliente inclui essa ID da sessão nas solicitações subsequentes para o servidor. O servidor usa a ID da sessão do cliente para carregar o objeto da sessão adequado para o contexto HTTP atual.

Padrão de Troca de Mensagens do Canal HttpCookieSession

Este exemplo permite sessões para cenários semelhantes a ASMX. Na parte inferior da nossa pilha de canais, temos o transporte HTTP que dá suporte a IRequestChannel e IReplyChannel. O trabalho do canal é fornecer sessões para os níveis mais altos da pilha de canais. O exemplo implementa dois canais (IRequestSessionChannel e IReplySessionChannel) que viabilizam as sessões.

Canal de Serviço

O exemplo fornece um canal de serviço na classe HttpCookieReplySessionChannelListener. Essa classe implementa a interface IChannelListener e converte o canal IReplyChannel na parte inferior da pilha de canais em um IReplySessionChannel. Esse processo pode ser dividido nas seguintes partes:

  • Quando o ouvinte de canais é aberto, ele aceita um canal interno do ouvinte interno. Como o ouvinte interno é um ouvinte de datagrama e o tempo de vida de um canal aceito é dissociado do tempo de vida do ouvinte, podemos fechar o ouvinte interno e manter apenas o canal interno

                this.innerChannelListener.Open(timeoutHelper.RemainingTime());
    this.innerChannel = this.innerChannelListener.AcceptChannel(timeoutHelper.RemainingTime());
    this.innerChannel.Open(timeoutHelper.RemainingTime());
    this.innerChannelListener.Close(timeoutHelper.RemainingTime());
    
  • Quando o processo em aberto é concluído, configuramos um loop de mensagens para receber as mensagens do canal interno.

    IAsyncResult result = BeginInnerReceiveRequest();
    if (result != null && result.CompletedSynchronously)
    {
       // do not block the user thread
       this.completeReceiveCallback ??= new WaitCallback(CompleteReceiveCallback);
       ThreadPool.QueueUserWorkItem(this.completeReceiveCallback, result);
    }
    
  • Quando uma mensagem chega, o canal de serviço examina o identificador da sessão e faz a demultiplexação para o canal de sessão apropriado. O ouvinte de canais mantém um dicionário que mapeia os identificadores da sessão para as instâncias do canal de sessão.

    Dictionary<string, IReplySessionChannel> channelMapping;
    

A classe HttpCookieReplySessionChannel implementa IReplySessionChannel. Os níveis mais altos da pilha de canais chamam o método ReceiveRequest para ler as solicitações dessa sessão. Cada canal de sessão tem uma fila de mensagens privada, que é preenchida pelo canal de serviço.

InputQueue<RequestContext> requestQueue;

Quando alguém chama o método ReceiveRequest e não há mensagens na fila de mensagens, o canal aguarda um tempo especificado para se desligar. Isso limpa os canais de sessão criados para clientes que não são do WCF.

Usamos o channelMapping para acompanhar o ReplySessionChannels, e não fechamos nossos canais subjacentes innerChannel até que todos os canais aceitos tenham sido fechados. Dessa forma, HttpCookieReplySessionChannel pode existir após o tempo de vida de HttpCookieReplySessionChannelListener. Também não precisamos nos preocupar se o ouvinte receberá o lixo coletado abaixo de nós, pois os canais aceitos mantêm uma referência ao ouvinte por meio do retorno de chamada OnClosed.

Canal do cliente

O canal do cliente correspondente está na classe HttpCookieSessionChannelFactory. Durante a criação do canal, a fábrica de canais encapsula o canal de solicitação interna com um HttpCookieRequestSessionChannel. A classe HttpCookieRequestSessionChannel encaminha as chamadas para o canal de solicitação subjacente. Quando o cliente fecha o proxy, HttpCookieRequestSessionChannel envia uma mensagem para o serviço que indica que o canal está sendo fechado. Assim, a pilha de canais de serviço pode desligar normalmente o canal de sessão que está em uso.

Associação e Elemento de Associação

Depois de criar os canais de serviço e de cliente, a próxima etapa é integrá-los ao runtime do WCF. Os canais são expostos ao WCF por meio das associações e dos elementos de associação. Uma associação consiste em um ou muitos elementos de associação. O WCF oferece várias associações definidas pelo sistema, por exemplo, BasicHttpBinding ou WSHttpBinding. A classe HttpCookieSessionBindingElement contém a implementação do elemento de associação. Ele substitui os métodos de criação do ouvinte de canais e da fábrica de canais, para fazer as instanciações necessárias do ouvinte de canais ou da fábrica de canais.

O exemplo usa declarações de política para a descrição do serviço. Isso permite que o exemplo publique os requisitos de canal para outros clientes que podem consumir o serviço. Por exemplo, esse elemento de associação publica declarações de política para permitir que os possíveis clientes saibam que ele permite sessões. Como o exemplo habilita a propriedade ExchangeTerminateMessage na configuração do elemento de associação, ele adiciona as declarações necessárias para mostrar que o serviço permite uma ação adicional de troca de mensagens para encerrar a conversa da sessão. Os clientes podem usar essa ação. O código WSDL a seguir mostra as declarações de política criadas no HttpCookieSessionBindingElement.

<wsp:Policy wsu:Id="HttpCookieSessionBinding_IWcfCookieSessionService_policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsp:ExactlyOne>
<wsp:All>
<wspe:Utf816FFFECharacterEncoding xmlns:wspe="http://schemas.xmlsoap.org/ws/2004/09/policy/encoding"/>
<mhsc:httpSessionCookie xmlns:mhsc="http://samples.microsoft.com/wcf/mhsc/policy"/>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>

A classe HttpCookieSessionBinding é uma associação fornecida pelo sistema, que usa o elemento de associação descrito anteriormente.

Adição do Canal ao Sistema de Configuração

O exemplo fornece duas classes que expõem o canal de exemplo por meio da configuração. A primeira é um BindingElementExtensionElement para o HttpCookieSessionBindingElement. A maior parte da implementação é delegada para o HttpCookieSessionBindingConfigurationElement, que é derivado do StandardBindingElement. O HttpCookieSessionBindingConfigurationElement tem propriedades que correspondem às propriedades no HttpCookieSessionBindingElement.

Seção de Extensão do Elemento de Associação

A seção HttpCookieSessionBindingElementSection é uma BindingElementExtensionElement que expõe HttpCookieSessionBindingElement ao sistema de configuração. Com algumas substituições, são definidos o nome da seção de configuração, o tipo do elemento de associação e como criar o elemento de associação. Podemos registrar a seção de extensão em um arquivo de configuração da seguinte maneira:

<configuration>
    <system.serviceModel>
      <extensions>
        <bindingElementExtensions>
          <add name="httpCookieSession"
               type=
"Microsoft.ServiceModel.Samples.HttpCookieSessionBindingElementElement,
                    HttpCookieSessionExtension, Version=1.0.0.0,
                    Culture=neutral, PublicKeyToken=null"/>
        </bindingElementExtensions >
      </extensions>

      <bindings>
      <customBinding>
        <binding name="allowCookiesBinding">
          <textMessageEncoding messageVersion="Soap11WSAddressing10" />
          <httpCookieSession sessionTimeout="10" exchangeTerminateMessage="true" />
          <httpTransport allowCookies="true" />
        </binding>
      </customBinding>
      </bindings>
    </system.serviceModel>
</configuration>

Código de Teste

O código de teste para usar esse transporte de exemplo está disponível nos diretórios do Cliente e do Serviço. Ele consiste em dois testes: um teste usa uma associação com allowCookies definido como true no cliente. O segundo teste permite o desligamento explícito (usando o encerramento da troca de mensagens) na associação.

Ao executar o exemplo, você verá a saída a seguir:

Simple binding:
AddItem(10000,2): ItemCount=2
AddItem(10550,5): ItemCount=7
RemoveItem(10550,2): ItemCount=5
Items
10000, 2
10550, 3
Smart binding:
AddItem(10000,2): ItemCount=2
AddItem(10550,5): ItemCount=7
RemoveItem(10550,2): ItemCount=5
Items
10000, 2
10550, 3

Press <ENTER> to terminate client.

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. Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.

  3. Para compilar a solução, siga as instruções contidas em Como compilar as amostras do Windows Communication Foundation.

  4. Para executar a amostra em uma configuração de computador único ou entre computadores, siga as instruções contidas em Como executar as amostras do Windows Communication Foundation.