HttpCookieSession

HttpCookieSession 示例演示如何生成自定义协议通道,以使用 HTTP Cookie 进行会话管理。 此通道支持 Windows Communication Foundation (WCF) 服务和 ASMX 客户端之间或 WCF 客户端与 ASMX 服务之间的通信。

当客户端在基于会话的 ASMX Web 服务中调用 Web 方法时,ASP.NET 引擎执行以下作:

  • 生成唯一 ID(会话 ID)。

  • 生成会话对象并将其与唯一 ID 相关联。

  • 将唯一 ID 添加到 Set-Cookie HTTP 响应标头,并将其发送到客户端。

  • 根据客户端发送到它的会话 ID 在后续调用中标识客户端。

客户端在其后续对服务器的请求中包含此会话 ID。 服务器使用客户端的会话 ID 为当前 HTTP 上下文加载相应的会话对象。

HttpCookieSession 通道消息交换模式

此示例可为类似ASMX的场景启用会话功能。 在我们的通道堆栈底部,我们具有支持 IRequestChannelIReplyChannel的 HTTP 传输。 通道的任务是向通道堆栈中的更高层提供会话。 此示例实现支持会话的两个通道(IRequestSessionChannelIReplySessionChannel)。

服务通道

此示例在HttpCookieReplySessionChannelListener类中提供服务通道。 此类实现 IChannelListener 接口,并将通道堆栈中位于较低层的 IReplyChannel 通道转换为 IReplySessionChannel。 此过程可以分为以下部分:

  • 当通道侦听器打开时,它接受来自其内部侦听器的内部通道。 由于内部侦听器是数据报侦听器,并且接受通道的生存期与侦听器的生存期分离,因此我们可以关闭内部侦听器,并且只保留内部通道

                this.innerChannelListener.Open(timeoutHelper.RemainingTime());
    this.innerChannel = this.innerChannelListener.AcceptChannel(timeoutHelper.RemainingTime());
    this.innerChannel.Open(timeoutHelper.RemainingTime());
    this.innerChannelListener.Close(timeoutHelper.RemainingTime());
    
  • 打开的进程完成后,我们设置了一个消息循环,用于从内部通道接收消息。

    IAsyncResult result = BeginInnerReceiveRequest();
    if (result != null && result.CompletedSynchronously)
    {
       // do not block the user thread
       this.completeReceiveCallback ??= new WaitCallback(CompleteReceiveCallback);
       ThreadPool.QueueUserWorkItem(this.completeReceiveCallback, result);
    }
    
  • 当消息到达后,服务通道检查会话标识符并多路分解到相应的会话通道。 通道侦听器维护一个字典,该字典将会话标识符映射到会话通道实例。

    Dictionary<string, IReplySessionChannel> channelMapping;
    

HttpCookieReplySessionChannel 实现 IReplySessionChannel。 通道堆栈的较高级别调用 ReceiveRequest 该方法来读取此会话的请求。 每个会话通道都有一个由服务通道填充的专用消息队列。

InputQueue<RequestContext> requestQueue;

如果有人调用 ReceiveRequest 该方法且消息队列中没有消息,通道会在关闭自身之前等待指定的时间量。 这会清理为非 WCF 客户端创建的会话通道。

我们使用 channelMapping 跟踪 ReplySessionChannels,并且在所有已接受的通道全部关闭之前不会关闭基础 innerChannel。 这种方法 HttpCookieReplySessionChannel 可以存在于 HttpCookieReplySessionChannelListener 的生命周期之外。 我们也无需担心侦听器会在我们下面收集垃圾,因为已接受的通道通过 OnClosed 回调保留对其侦听器的引用。

客户端通道

相应的客户端通道位于类中 HttpCookieSessionChannelFactory 。 在通道创建过程中,通道工厂使用HttpCookieRequestSessionChannel包装内部请求通道。 该 HttpCookieRequestSessionChannel 类将呼叫转发至底层请求通道。 当客户端关闭代理时, HttpCookieRequestSessionChannel 向服务发送一条消息,指示通道正在关闭。 因此,服务通道堆栈可以正常关闭正在使用的会话通道。

绑定和绑定元素

创建服务和客户端通道后,下一步是将它们集成到 WCF 运行时。 通道通过绑定和绑定元素公开给 WCF。 绑定由一个或多个绑定元素组成。 WCF 提供多个系统定义的绑定;例如,BasicHttpBinding 或 WSHttpBinding。 该 HttpCookieSessionBindingElement 类包含绑定元素的实现。 它重写通道侦听器和通道工厂创建方法,以进行必要的通道侦听器或通道工厂实例化。

该示例在服务描述中使用了策略断言。 这允许示例将其通道要求发布到其他可以使用该服务的客户端。 例如,此绑定元素发布策略断言,让潜在客户端知道它支持会话。 由于该示例启用 ExchangeTerminateMessage 绑定元素配置中的属性,从而添加必要的断言,以显示服务支持额外的消息交换操作来终止会话对话。 然后,客户可以使用此操作。 以下 WSDL 代码显示从 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>

HttpCookieSessionBinding 类是一个系统提供的绑定,它使用前面所述的绑定元素。

将通道添加到配置系统

此示例提供了两个类,它们通过配置公开示例通道。 第一个类是适用于 BindingElementExtensionElementHttpCookieSessionBindingElement。 批量实现委派给从 HttpCookieSessionBindingConfigurationElement 派生的 StandardBindingElementHttpCookieSessionBindingConfigurationElement 的属性与 HttpCookieSessionBindingElement 上的属性相对应。

绑定元素扩展节

HttpCookieSessionBindingElementSection 节是一个 BindingElementExtensionElement,它向配置系统公开 HttpCookieSessionBindingElement。 通过对配置节名称进行一些重写,可以定义绑定元素的类型以及如何创建绑定元素。 然后,我们可以在配置文件中注册扩展部分,如下所示:

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

测试代码

客户端和服务目录中提供了使用此示例传输的测试代码。 它包含两个测试 - 一个测试在客户端使用 allowCookies 设置为 true 的绑定。 第二个测试在该绑定上实现显式关闭(使用终止消息交换)。

运行示例时,应会看到以下输出:

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.

设置、生成和运行示例

  1. 使用以下命令安装 ASP.NET 4.0。

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. 确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。

  3. 要生成解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。

  4. 若要在单台计算机或跨计算机配置中运行示例,请按照 运行 Windows Communication Foundation 示例中的说明进行操作。