您的位置:首页 > 理论基础 > 计算机网络

ASP.NET 3.5核心编程学习笔记(33):HttpSessionState简介

2011-04-24 11:47 597 查看
  对于会话状态值的存储,HttpSessionState类提供了一个基于字典的模型。只有同一会话上下文中的请求(即由同一个用户发出的多个页面请求)才可以访问会话状态。会话状态的存储和发布方式有很多,其中包括在Web Farm和Web Garden环境下的。但在默认情况下,会话状态由ASP.NET工作线程持有。

  会话状态的可扩展模型提供了两种方案:

  1. 可对ASP.NET现有的会话状态机制进行局部的自定义(如:创建Oracle会话提供程序或创建能控制ID生成的模块)。

  2. 可以将整个标准的会话状态HTTP模块替换成其他的自定义会话状态HTTP模块。

  第一种方案更容易实现,但可自定义的功能比较有限。第二种方案的编码较复杂,但提供更好的灵活性。

会话状态HTTP模块

  会话状态是一个集合,由Page类的Session属性暴露出来,其类型为HttpSessionState。该类是封闭的,实现了ICollection和IEnumerable接口。该类的实例会在每个支持会话的请求启动时创建。该集合填充的数据会以键/值对的形式从指定的介质中读取,之后会被附加到请求上下文上。Page的Session属性只是映射到HttpContext类的Session属性而已。

  HTTP模块通过某些特殊的提供程序来管理会话状态的存储与获取。负责为每个连接到应用程序的用户建立会话状态的ASP.NET模块,是一个被称为SessionStateModule的HTTP模块。SessionStateModule对象实现了IHttpModule接口,提供了ASP.NET应用程序的会话状态服务。

  但作为HTTP模块,SessionStateModule需要通过相对简单的编程接口(IHttpModule接口只有Init和Dispose方法)来执行许多非常复杂的任务,而且其中的许多操作会严重影响Web应用程序的属性和功能。会话状态模块会在即将处理某个给定请求的HttpApplication对象创建的过程中调用,该模块需要负责生成或获取一个唯一会话ID字符串,以便通过状态提供程序(如SQL Server或Web服务器的内存)来存储和获取状态数据。

状态客户端管理器

  当会话状态HTTP模块被调用时,它会读取web.config文件<sessionState>区段中的设置,并决定当前应用程序选用何种“状态客户端管理器”。状态客户端管理器是一种负责存/取当前活动会话数据的组件。SessionStateModule组件会对状态客户端管理器进程进行查询,来获得给定会话的键/值对。

  ASP.NET中有4种会话状态的处理方式。会话状态可存储在ASP.NET工作线程中,可以在一个叫aspnet_state.exe外部(甚至是远程)进程中维护,可以由通过SQL Server或其他数据库表来管理。最后一种方式是将会话数据存储在自定义的组件中。下表对各种方案做了总结:





  SessionStateMode枚举类型包含状态客户端提供程序可用的选项。InProc选项的访问速度最快,但应记住,在会话中存储的数据越多,Web服务器内存的占用量也越大,从而会造成性能瓶颈。如果打算采用进程外(out-of-process)解决方案,则应考虑序列化与反序列化过程带来的影响。

  会话状态模块会基于web.config文件<sessionState>区段读取的设置来确定状态提供程序。接着,它会对应用程序的状态提供程序进行实例化和初始化。每种提供程序自身能够执行初始化,不同类型的提供程序该过程会有所差异。

  所有状态提供程序都暴露了用于与主调程序进行通信的方法,整个架构如下图所示:



  所有实际的状态提供程序对象都统一继承于一个基类:SessionStateStoreProviderBase类。

HttpSessionState对象的创建

  状态模块负责会话状态的获取,并将其附加到当前会话中运行的每个请求上下文中。会话状态在HttpApplication.AcquireRequestState事件引发后才可用,并在HttpApplication.ReleaseRequestState事件引发后将数据丢弃且不可恢复。这意味着随后引发Session_End事件时,所有状态都已消失。

  在HttpApplication.AcquireRequestState事件引发时,会话模块会为请求创建HttpSessionState对象。此时,HttpSessionStae对象会获得一个会话ID和一个会话字典。会话字典实际上是一种状态值得的集合,可通过页面的Session属性访问。

  在刚刚发起新会话时,数据字典是一个空的对象。如果该模块处理的是现有会话的请求,那么当前活动的会话状态提供程序会对数据进行反序列化,并填充该数据字典。在请求结束时,若页面请求修改当前字典的内容,那么它会执行序列化过程,并将数据发送给状态提供程序。整个过程如下图所示:



会话状态访问的同步

  在Web页面调用Session属性时,它实际上访问的是数据的副本,位于本地的内存中。如果其他页面(同一会话中的)试图以并发方式访问会话状态,会发生什么情况?在这种情况下,当前请求最终可能会获得不一致的数据,或者说数据不是最新的。

  为避免这种情况的发生,会话状态模块实现了读取方法和写入方法的锁定机制,使要访问状态数据的请求排队执行。对会话状态写入访问的页面会保持写入方法在当前会话中处于锁定状态,直到当前请求结束。通过将@Page指令的EnableSessionState属性设置为true,页面便获得会话状态的写入访问权限。只拥有会话状态读取访问权限的页面(如EnableSessionState属性为ReadOnly)会保持读取方法在当前会话中处于锁定状态,直到当前请求结束。

  如果页面请求设置了读取方法的锁(reader lock),其他并发运行的请求则不能更新会话状态,但允许读取。如果页面请求对会话状态设置了编写器的锁(writer lock),其他页面不论是读取还是写入,都会被锁定。

  会话状态的并发访问在实际当中并不常见。若某个页面带有多个框架(frame),或用户打开了同一页面的两个副本或同一应用程序的多个页面,可能会发生这种情况。此外,若使用启用会话的HTTP处理程序对一个嵌入的资源(图像或CSS文件)进行服务时,也可能发生。在默认情况下,并发访问是不会发生的。然而,显式地声明页面对会话状态的使用模式(读/写、只读或不使用),不失为一种好的编程习惯。为此,只需设置@Page指令的EnableSessionState属性即可。

HttpSessionStae类的属性

  HttpSessionState类定义在System.Web.SessionState命名空间中。这是一个泛型集合类,实现了ICollection接口。下表列出了HttpSessionState类的属性:



  出于同步方面的考虑使HttpSessionState类成为非常特殊的集合类。如前所述,同步机制是在SessionStateModule组件中实现的,该组件确保同一时刻只有一个线程可以访问会话状态。然而,由于HttpSessionState实现了ICollection接口,包含了对IsSynchronized和SyncRoot的实现。应注意,IsSynchronized和SyncRoot是同步集合特有的属性,与之前所讨论的会话同步毫不相干。从技术角度讲,HttpSessionState本身不支持同步,但通过它访问的会话状态是同步的。

HttpSessionState类的方法

  下表列出了HttpSessionState类的方法:



  当运行终止当前请求的过程时,会话状态模块会检查一下内部状态,确认用户是否发出取消会话的命令。如果该标志被设置(Abandon方法被调用),所有响应cookie都会被移除,终止会话的过程会被启动。但那并不意味着Session_End事件一定会被触发。

  首先,仅当会话模式为InProc时,Session_End事件才会被触发。其次,如果会话字典为空,且应用程序中不存在实际的会话状态数据,该事件则不会被触发。换言之,若会话自然关闭或调用过Abandon,且至少有一个请求已完成,Session_End才会被触发。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: