在 ASP.NET 中实现会话状态的基础

发布时间:2013-09-19 11:33:46来源:阅读(1358)

    在 Web 应用程序这样的无状态环境中,了解会话状态的概念并没有实际的意义。尽管如此,有效的状态管理对于大多数 Web 应用程序来说都是一个必备的功能。Microsoft® ASP.NET 以及许多其他服务器端编程环境都提供了一个抽象层,允许应用程序基于每个用户和每个应用程序存储持久性数据。


    需要特别注意的是,Web 应用程序的会话状态是应用程序在不同的请求中缓存和检索的数据。会话表示用户在与该站点连接期间发送的所有请求,会话状态是用户在会话期间生成和使用的持久性数据的集合。每个会话的状态都彼此独立,而且在用户会话结束时就不复存在了。

    会话状态与构成 HTTP 协议和规范的任何逻辑实体都没有对应关系。会话是由服务器端开发环境(例如传统的 ASP 和 ASP.NET)构建的抽象层。ASP.NET 展示会话状态的方式以及会话状态的内部实现方式都取决于平台的基础结构。因此,传统的 ASP 和 ASP.NET 以完全不同的方式来实现会话状态,预计在下一版的 ASP.NET 中会有进一步的改进和增强。

    本文讨论如何在 ASP.NET 1.1 中实现会话状态,以及如何在被管理的 Web 应用程序中优化会话状态管理。

    ASP.NET 会话状态概述
    会话状态并不是 HTTP 基础结构的一部分。也就是说,应该有一个结构组件将会话状态与每个传入请求绑定在一起。运行时环境(传统的 ASP 或 ASP.NET)能够接受 Session 之类的关键字,并使用它指示服务器上存储的数据块。要成功解析 Session 对象的调用,运行时环境必须将会话状态添加到正在处理的请求的调用上下文中。完成此操作的方式因平台而异,但它是有状态 Web 应用程序的基础操作。

    在传统的 ASP 中,会话状态是作为 ASP.dll 库中包含自由线程 COM 对象来实现的。(您对此很好奇吗?其实该对象的 CLSID 是 D97A6DA0-A865-11cf-83AF-00A0C90C2BD8。)此对象存储以名称/值对集合的方式组织的数据。“名称”占位符表示用来检索信息的关键字,而“值”占位符表示会话状态中存储的内容。名称/值对按照会话 ID 进行分组,这样,每个用户看到的只是他/她自己创建的名称/值对。

    在 ASP.NET 中,会话状态的编程接口与传统的 ASP 几乎是相同的。但它们的基础实现是完全不同的,前者比后者更具有灵活性、可扩展性和更强的编程功能。深入研究 ASP.NET 会话状态之前,让我们简单回顾一下 ASP.NET 会话基础结构的某些结构功能。

    在 ASP.NET 中,任何传入 HTTP 请求都要通过 HTTP 模块管道进行传输。每个模块都可以筛选并修改请求所携带的大量信息。与每个请求关联的信息叫做“调用上下文”,编程中用 HttpContext 对象来表示。我们不应将请求的上下文视为状态信息的另一个容器,虽然它提供的 Items 集合只是一个数据容器。HttpContext 对象不同于所有其他状态对象(例如,Session、Application 和 Cache),因为它的有限生命周期超出了处理请求所需的时间。当请求通过一系列注册的 HTTP 模块后,其 HttpContext 对象将包含状态对象的引用。当最终可以处理请求时,关联的调用上下文将绑定到特定会话 (Session) 和全局状态对象(Application 和 Cache)。

    负责设置每个用户的会话状态的 HTTP 模块为 SessionStateModule。该模块的结构是根据 IHttpModule 接口设计的,它为 ASP.NET 应用程序提供大量与会话状态有关的服务。包括生成会话 ID、Cookieless 会话管理、从外部状态提供程序中检索会话数据以及将数据绑定到请求的调用上下文。

    HTTP 模块并不在内部存储会话数据。会话状态始终保存在名为“状态提供程序”的外部组件中。状态提供程序完全封装会话状态数据,并通过 IStateClientManager 接口的方法与其他部分进行通信。会话状态 HTTP 模块调用该接口上的方法来读取并保存会话状态。ASP.NET 1.1 支持三种不同的状态提供程序,如表 1 所示。

    表 1:状态客户端提供程序

    提供程序 说明
    InProc 会话值在 ASP.NET 辅助进程(Microsoft® Windows Server™ 2003 中的 ASPnet_wp.exe 或 w3wp.exe)的内存中保持为活动对象。这是默认选项。
    StateServer 会话值被序列化并存储在单独进程 (ASPnet_state.exe) 的内存中。该进程还可以在其他计算机上运行。
    SQLServer 会话值被序列化并存储在 Microsoft® SQL Server™ 表中。SQL Server 的实例可以在本地运行,也可以远程运行。

    会话状态 HTTP 模块将从 web.config 文件的 部分读取当前选定的状态提供程序。


    上述代码实际上访问的是 HTTP 模块创建的会话值在本地内存中的副本,从特定状态提供程序(参见图 1)中读取数据。如果其他页面也试图同步访问该会话状态,又会如何呢?这种情况下,当前的请求可能会停止处理不一致的数据或过时的数据。为了避免这种情况,会话状态模块将实现一个读取器/写入器锁定机制,并对状态值的访问进行排队。对会话状态具有写入权限的页面将保留该会话的写入器锁定,直到请求终止。

    通过将 @Page 指令的 EnableSessionState 属性设置为 true,页面可以请求会话状态的写入权限。(这是默认设置)。但是,页面还可以拥有会话状态的只读权限,例如,当 EnableSessionState 属性被设置为 ReadOnly 时。在这种情况下,模块将保留该会话的读取器锁定,直到该页面的请求结束。结果将发生并发读取。

    如果页面请求设置一个读取器锁定,同一会话中同时处理的其他请求将无法更新会话状态,但是至少可以进行读取。也就是说,如果当前正在处理会话的只读请求,那么等候的只读请求要比需要完全访问权限的请求具有更高的优先权。如果页面请求为会话状态设置一个写入器锁定,那么所有其他页面都将被阻止,无论它们是否要读取或写入内容。例如,如果同时有两个框架试图在 Session 中写入内容,一个框架必须等到另一个框架完成后才能写入。

    比较状态提供程序
    默认情况下,ASP.NET 应用程序将会话状态存储在辅助进程的内存中,特别是 Cache 对象的专用槽中。选中 InProc 模式时,会话状态将存储在 Cache 对象内的槽中。此槽被标记为专用槽,无法通过编程方式进行访问。换句话说,如果枚举 ASP.NET 数据缓存中的所有项目,将不会返回类似于给定会话状态的任何对象。Cache 对象提供两类槽:专用槽和公用槽。编程人员可以添加和处理公用槽,但专用槽只能由系统(特别是 system.web 部件中定义的类)专用。

    每个活动会话的状态都占用缓存中的一个专用槽。槽的名称根据会话 ID 进行命名,其值是名为 SessionStateItem 的内部未声明类的一个实例。InProc 状态提供程序获取会话 ID 并在缓存中检索对应的元素。然后将 SessionStateItem 对象的内容输入 HttpSessionState 词典对象,并由应用程序通过 Session 属性进行访问。请注意,ASP.NET 1.0 中存在一个错误,使 Cache 对象的专用槽可以通过编程方式进行枚举。如果您在 ASP.NET 1.0 下运行以下代码,则能够枚举与每个当前活动会话状态中包含的对象对应的项目。

    foreach(DictionaryEntry elem in Cache)
    {
    Response.Write(elem.Key + ": " + elem.Value.ToString());
    }

    此错误已经在 ASP.NET 1.1 中得到解决,当您枚举缓存的内容时,将不再列出任何系统槽。

    到目前为止,InProc 可能是最快的访问选项。但请记住,会话中存储的数据越多,Web 服务器所消耗的内存就越多,这样会潜在地增加性能降

关键字

上一篇: PHP中的XML应用

下一篇: ASP提速技巧五则