更新:2007 年 11 月
描述自定义会话状态存储提供程序实现,并演示示例提供程序实现。
使用 ASP.NET 会话状态可以将用户会话数据存储在不同的源中
。默认情况下,会话状态值和信息都存储在 ASP.NET 进程的内存中。一个方法是将会话数据存储在状态服务器中,状态服务器将会话数据保存在单独的进程中,如果 ASP.NET 应用程序关闭再重新启动,则它会保留会话数据。另一个方法是将会话数据存储在 SQL Server 数据库中,这种情况下会话数据可由多个 Web 服务器共享。
可以使用 ASP.NET 附带的会话状态存储,也可以实现自己的会话状态存储提供程序。由于下列原因,您可以创建自定义会话状态存储提供程序:
可以通过创建一个继承 SessionStateStoreProviderBase 类的类,来实现自定义会话状态存储提供程序。有关更多信息,请参见本主题后面的“必需的类”一节。
会话状态由 SessionStateModule 类进行管理,在请求过程中的不同时间,该类调用会话状态存储提供程序在数据存储区中读写会话数据。请求开始时,SessionStateModule 实例通过调用 GetItemExclusive 方法或 GetItem 方法(如果 EnableSessionState 页属性已设置为 ReadOnly)从数据源检索数据。请求结束时,如果修改了会话状态值,则 SessionStateModule 实例调用 SessionStateStoreProviderBase..::.SetAndReleaseItemExclusive 方法将更新的值写入会话状态存储区。SessionStateModule 调用 SessionStateStoreProviderBase 实现的其他成员来初始化一个新会话,并在调用 HttpSessionState..::.Abandon 方法时从数据存储区中删除会话数据。SessionStateStoreProviderBase 类的每个成员稍后将在本主题的“必需的类”一节中进行更详细的讨论。
SessionStateModule 自己确定 SessionID 值,而不依赖于会话状态存储提供程序进行确定。如果需要,可以通过创建继承 ISessionIDManager 接口的类来实现自定义 SessionIDManager。有关更多信息,请参见 ISessionIDManager 中的“备注”一节。
SessionStateModule 将恢复为 ASP.NET 进程标识以访问任何安全资源,例如数据库服务器。可以指定 SessionStateModule 实例模拟 IIS 提供的标识,方法是将 <sessionState> 配置元素的 useHostingIdentity 属性设置为 false。例如,如果已经将 IIS 应用程序配置为使用 Windows 集成安全性,并且希望 ASP.NET 模拟 IIS 提供的标识进行会话管理,则在应用程序的 Web.config 文件的 <system.web> 配置节中指定 <identity impersonate="true" />,并将 <sessionState> 配置元素的 useHostingIdentity 属性设置为 false。如果 useHostingIdentity 属性为 true,则 ASP.NET 在连接数据源时将模拟进程标识或提供给 <identity> 配置元素的用户凭据(如果进程标识和用户凭据存在)。有关 ASP.NET 进程标识的更多信息,请参见配置 ASP.NET 进程标识和 ASP.NET 模拟。
ASP.NET 应用程序是多线程的,因此可支持对多个并发请求的响应。多个并发请求可能会试图访问同一会话信息。假设有这样一种情况,框架集中的多个框架全部引用同一应用程序中的 ASP.NET 网页。框架集中每个框架的独立请求可以在 Web 服务器的不同线程上并发执行。如果每个框架的 ASP.NET 页都访问会话状态变量,则可能会有多个线程并发访问会话存储区。为避免会话存储区中的数据冲突和意外的会话状态行为,SessionStateModule 和 SessionStateStoreProviderBase 类提供了一种功能,能在执行 ASP.NET 页期间以独占方式锁定特定会话的会话存储项。请注意,如果 EnableSessionState 属性标记为 ReadOnly,则不会对会话存储项设置锁定。但是,同一应用程序中的其他 ASP.NET 页也许可以写入会话存储区,因此对存储区中只读会话数据的请求可能仍然必须等待锁定数据被释放。
在对 GetItemExclusive 方法的调用中,请求开始时即对会话存储数据设置锁定。请求完成后,在调用 SetAndReleaseItemExclusive 方法期间释放锁定。
如果 SessionStateModule 实例在调用 GetItemExclusive 或 GetItem 方法过程中遇到锁定的会话数据,则该实例每隔半秒重新请求一次该会话数据,直到锁定被释放或 ExecutionTimeout 属性中指定的时间已经过去。如果请求超时,SessionStateModule 将调用 ReleaseItemExclusive 方法来释放会话存储数据,然后立即请求该会话存储数据。
为当前响应调用 SetAndReleaseItemExclusive 方法之前,锁定的会话存储数据可能已经在单独的线程上由对 ReleaseItemExclusive 方法的调用释放。这可能导致 SessionStateModule 实例设置和释放已经由其他会话释放和修改的会话状态存储数据。为避免这种情况,SessionStateModule 为每个请求都提供一个锁定标识符,以便修改锁定的会话存储数据。仅当数据存储区中的锁定标识符与 SessionStateModule 提供的锁定标识符匹配时,会话存储数据才能修改。
为会话调用 Abandon 方法时,将使用 RemoveItem 方法从数据存储区中删除该会话的数据。否则,这些数据将保留在会话数据存储区中,供以后对该会话的请求使用。
删除过期会话数据的机制取决于数据源的功能。如果可以将数据源配置为根据会话 Timeout 属性删除过期会话数据,则可以使用 SetItemExpireCallback 方法引用 Session_OnEnd 事件的委托并在删除过期会话数据时引发该委托。
为维护会话范围,会话状态提供程序为每个应用程序单独存储会话信息。这使多个 ASP.NET 应用程序能够使用同一数据源而不会在出现重复的会话标识符时产生冲突。
由于会话状态存储提供程序为每个应用程序单独存储会话信息,因此必须确保数据架构、查询和更新包括应用程序名称。例如,下面的命令可以用于从数据库检索会话数据。
SELECT * FROM Sessions
WHERE SessionID = 'ABC123' AND ApplicationName = 'MyApplication'
或者,也可以将会话标识符和应用程序名称的组合存储为会话状态数据存储区中的项的唯一标识符。
若要实现会话状态存储提供程序,请创建一个继承 SessionStateStoreProviderBase 抽象类的类。SessionStateStoreProviderBase 类又继承 ProviderBase 抽象类,因此还必须实现 ProviderBase 类必需的成员。下表列出了必须从 ProviderBase 和 SessionStateStoreProviderBase 抽象类实现的属性和方法,并提供了每个属性和方法的说明。若要查看每个成员的实现,请参见会话状态存储提供程序示例。
必需的 ProviderBase 成员
必需的 SessionStateStoreProvider 成员
若要查看管理 Access 数据库中会话信息的自定义会话状态存储提供程序的示例实现,请参见会话状态存储提供程序示例。
概念