ASP.NET 状态管理建议

更新:2007 年 11 月

状态管理是您对同一页或不同页的多个请求维护状态和页信息的过程。与所有基于 HTTP 的技术一样,Web 窗体页是无状态的,这意味着它们不自动指示序列中的请求是否全部来自相同的客户端,或者单个浏览器实例是否一直在查看页或站点。此外,到服务器的每一往返过程都将销毁并重新创建页;因此,如果超出了单个页的生命周期,页信息将不存在。有关服务器往返过程和 Web 窗体页生命周期的更多信息,请参见 ASP.NET 页生命周期概述

ASP.NET 提供多种方式来在服务器往返过程之间维护状态。对这些状态管理选项的选择主要取决于您的应用程序,并且应基于以下条件:

  • 需要存储的信息量有多大?

  • 客户端是接受持久性的还是内存中的 Cookie?

  • 要将信息存储在客户端还是服务器上?

  • 信息是否是敏感信息?

  • 您对应用程序设定了什么样的性能和带宽条件?

  • 目标浏览器和设备具有什么样的功能?

  • 您是否需要储存基于用户的信息?

  • 信息需要存储多长时间?

  • 您使用 Web 场(多个服务器)、Web 园(一个计算机上的多个进程)还是单个进程来运行应用程序?

客户端状态管理选项

使用客户端选项存储页信息不使用服务器资源。这些选项往往具有最低的安全性但具有较快的服务器性能,因为对服务器资源的要求是适度的。但是,由于必须将信息发送到客户端来进行存储,因此对于以这种方式可以存储多少信息存在一定的客观限制。

以下是 ASP.NET 支持的客户端状态管理选项:

  • 视图状态

  • 控件状态

  • 隐藏字段

  • Cookie

  • 查询字符串

视图状态

Web 窗体页提供 ViewState 属性作为内置结构,在对同一页的多个请求间自动保留值。视图状态作为页中的隐藏域来进行维护。有关更多信息,请参见 ASP.NET 状态管理概述

可以使用视图状态在页回发到自身时跨越往返过程存储您自己的页特定值。例如,如果您的应用程序正在维护用户特定的信息(即,该信息在页上使用,但不是任何控件所必需的部分),则可以使用视图状态存储该信息。

使用视图状态的优点为:

  • 不需要任何服务器资源   视图状态包含在页代码内的结构中。

  • 实现简单   视图状态无需使用任何自定义编程。默认情况下对控件启用状态数据的维护。

  • 增强的安全功能   视图状态中的值经过哈希计算和压缩,并且针对 Unicode 实现进行编码,其安全性要高于使用隐藏域。

使用视图状态的缺点为:

  • 性能注意事项   由于视图状态存储在页本身,因此如果存储较大的值,用户显示页和发布页时的速度可能会减慢。尤其是对移动设备,其带宽通常是有限的。

  • 设备限制   移动设备可能没有足够的内存容量来存储大量的视图状态数据。

  • **潜在的安全风险   **视图状态存储在页上的一个或多个隐藏域中。虽然视图状态以哈希格式存储数据,但它可以被篡改。如果直接查看页输出源,可以看到隐藏域中的信息,这导致潜在的安全性问题。有关更多信息,请参见 ASP.NET Web 应用程序安全性Web 应用程序的基本安全实施策略

控件状态

ASP.NET 页框架提供了 ControlState 属性作为在服务器往返过程中存储自定义控件数据的方法。例如,如果您编写的自定义控件使用多个不同的选项卡来显示不同的信息,为使此控件能够按预期方式工作,控件需要知道在往返过程中哪个选项卡被选中。视图状态可用于此目的,但是开发人员可能在页级将视图状态关闭,这实际上破坏了您的控件。与视图状态不同,控件状态不能被关闭,因此它提供了存储控件状态数据的更可靠方法。

使用控件状态的优点为:

  • 不需要任何服务器资源   默认情况下,控件状态存储在页上的隐藏域中。

  • 可靠性   因为控件状态不像视图状态那样可以关闭,控件状态是管理控件的状态的更可靠方法。

  • 通用性   可以编写自定义适配器来控制如何存储控件状态数据和控件状态数据的存储位置。

使用控件状态的缺点为:

  • 需要一些编程   虽然 ASP.NET 页框架为控件状态提供了基础,但是控件状态是一个自定义的状态保持机制。为了充分利用控件状态,您必须编写代码来保存和加载控件状态。

隐藏字段

可以在页上的隐藏域中存储特定于页的信息,作为维护页的状态的一种方式。有关隐藏域的更多信息,请参见 ASP.NET 状态管理建议

如果使用隐藏域,最好在客户端上只存储少量经常更改的数据。

z1hkazw7.alert_note(zh-cn,VS.90).gif说明:

如果使用隐藏域,则必须使用 HTTP POST 方法向服务器提交页,而不是使用通过页 URL 请求该页的方法(HTTP GET 方法)向服务器提交页。

使用隐藏域的优点为:

  • 不需要任何服务器资源   隐藏域在页上存储和读取。

  • 广泛的支持   几乎所有浏览器和客户端设备都支持具有隐藏域的窗体。

  • 实现简单   隐藏域是标准的 HTML 控件,不需要复杂的编程逻辑。

使用隐藏域的缺点为:

  • 潜在的安全风险   隐藏域可以被篡改。如果直接查看页输出源,可以看到隐藏域中的信息,这导致潜在的安全性问题。您可以手动加密和解密隐藏域的内容,但这需要额外的编码和开销。如果关注安全,请考虑使用基于服务器的状态机制,从而不将敏感信息发送到客户端。有关更多信息,请参见 ASP.NET Web 应用程序安全性Web 应用程序的基本安全实施策略

  • 简单的存储结构   隐藏域不支持复杂数据类型。隐藏域只提供一个字符串值域存放信息。若要存储多个值,必须实现分隔的字符串以及用来分析那些字符串的代码。您可以手动分别将复杂数据类型序列化为隐藏域以及将隐藏域反序列化为复杂数据类型。但是,这需要额外的代码来实现。如果您需要将复杂数据类型存储在客户端上,请考虑使用视图状态。视图状态内置了序列化,并且将数据存储在隐藏域中。

  • 性能注意事项   由于隐藏域存储在页本身,因此如果存储较大的值,用户显示页和发布页时的速度可能会减慢。

  • 存储限制   如果隐藏域中的数据量过大,某些代理和防火墙将阻止对包含这些数据的页的访问。因为最大数量会随所采用的防火墙和代理的不同而不同,较大的隐藏域可能会出现偶发性问题。如果您需要存储大量的数据项,请考虑执行下列操作之一:

    • 将每个项放置在单独的隐藏域中。

    • 使用视图状态并打开视图状态分块,这样会自动将数据分割到多个隐藏域。

    • 不将数据存储在客户端上,将数据保留在服务器上。向客户端发送的数据越多,您的应用程序的表面响应时间越慢,因为浏览器需要下载或发送更多的数据。

Cookie 用于在客户端上存储少量经常更改的信息。这些信息与请求一起发送到服务器。有关创建和读取 Cookie 的详细信息,请参见 ASP.NET Cookie 概述

使用 Cookie 的优点为:

  • 可配置到期规则   Cookie 可以在浏览器会话结束时到期,或者可以在客户端计算机上无限期存在,这取决于客户端的到期规则。

  • 不需要任何服务器资源   Cookie 存储在客户端并在发送后由服务器读取。

  • 简单性   Cookie 是一种基于文本的轻量结构,包含简单的键值对。

  • 数据持久性   虽然客户端计算机上 Cookie 的持续时间取决于客户端上的 Cookie 过期处理和用户干预,Cookie 通常是客户端上持续时间最长的数据保留形式。

使用 Cookie 的缺点为:

  • 大小受到限制   大多数浏览器对 Cookie 的大小有 4096 字节的限制,尽管在当今新的浏览器和客户端设备版本中,支持 8192 字节的 Cookie 大小已愈发常见。

  • 用户配置为禁用   有些用户禁用了浏览器或客户端设备接收 Cookie 的能力,因此限制了这一功能。

  • 潜在的安全风险   Cookie 可能会被篡改。用户可能会操纵其计算机上的 Cookie,这意味着会对安全性造成潜在风险或者导致依赖于 Cookie 的应用程序失败。另外,虽然 Cookie 只能被将它们发送到客户端的域访问,历史上黑客已经发现从用户计算机上的其他域访问 Cookie 的方法。您可以手动加密和解密 Cookie,但这需要额外的编码,并且因为加密和解密需要耗费一定的时间而影响应用程序的性能。有关更多信息,请参见 ASP.NET Web 应用程序安全性Web 应用程序的基本安全实施策略

    z1hkazw7.alert_note(zh-cn,VS.90).gif说明:

    Cookie 通常用于为已知用户自定义内容的个性化情况。在大多数此类情况中,Cookie 是作为“标识”而不是“身份验证”。因此,通常保护用于标识的 Cookie 的方法是在 Cookie 中存储用户名、帐户名或唯一用户 ID(例如 GUID),然后用以访问站点的用户个性化结构中的信息。

查询字符串

查询字符串是在页 URL 的结尾附加的信息。有关更多信息,请参见 ASP.NET 状态管理概述

可以使用查询字符串来通过 URL 将数据提交回您的页或另一页上。查询字符串提供一种维护某些状态信息的简单但有限的方法。例如,它们是将信息从一页传送到另一页的简便的方法(例如,将产品号传递到将处理该产品号的另一页)。

使用查询字符串的优点为:

  • 不需要任何服务器资源   查询字符串包含在对特定 URL 的 HTTP 请求中。

  • 广泛的支持   几乎所有的浏览器和客户端设备均支持使用查询字符串传递值。

  • 实现简单   ASP.NET 完全支持查询字符串方法,其中包含了使用 HttpRequest 对象的 Params 属性读取查询字符串的方法。

使用查询字符串的缺点为:

  • 潜在的安全性风险   用户可以通过浏览器用户界面直接看到查询字符串中的信息。用户可将此 URL 设置为书签或发送给别的用户,从而通过此 URL 传递查询字符串中的信息。如果您担心查询字符串中的任何敏感数据,请考虑使用窗体(使用 POST 而不是查询字符串)中的隐藏域。有关更多信息,请参见 ASP.NET Web 应用程序安全性Web 应用程序的基本安全实施策略

  • 有限的容量   有些浏览器和客户端设备对 URL 的长度有 2083 个字符的限制。

客户端方法状态管理摘要

下表列出了 ASP.NET 可用的客户端状态管理选项,并提供了有关何时使用每个选项的建议。

状态管理选项

使用建议

视图状态

当您需要存储少量回发到自身的页信息时使用。使用 ViewState 属性可提供具有基本安全性的功能。

控件状态

当您需要在服务器的往返过程间存储少量控件状态信息时使用。

隐藏字段

当您需要存储少量回发到自身或另一页的页信息时使用,也可以在不存在安全性问题时使用。

z1hkazw7.alert_note(zh-cn,VS.90).gif说明:
只能在提交到服务器的页上使用隐藏域。

Cookie

当您需要在客户端存储少量信息以及不存在安全性问题时使用。

查询字符串

当您将少量信息从一页传输到另一页以及不存在安全性问题时使用。

z1hkazw7.alert_note(zh-cn,VS.90).gif说明:
只有在请求同一页,或通过链接请求另一页时,才能使用查询字符串。

服务器端状态管理选项

存储页信息的服务器端选项往往比客户端选项具有更高的安全性,但它们可能使用更多的 Web 服务器资源,这可能在信息存储量较大时导致伸缩性方面的问题。ASP.NET 提供几种选项来实现服务器端状态管理。有关更多信息,请参见 ASP.NET 状态管理概述

以下是 ASP.NET 支持的服务器端状态管理选项:

  • 应用程序状态

  • 会话状态

  • 配置文件属性

  • 数据库支持

应用程序状态

ASP.NET 通过 HttpApplicationState 类将应用程序状态提供为一种存储全局应用程序特定信息(对于整个应用程序都可见)的方法。应用程序状态变量实际上是 ASP.NET 应用程序的全局变量。有关更多信息,请参见 ASP.NET 应用程序状态概述

您可以在应用程序状态中存储应用程序特定的值,应用程序状态将由服务器来管理。有关更多信息,请参见 ASP.NET 状态管理概述

由多个会话共享并且不经常更改的数据是插入到应用程序状态变量的理想数据。

使用应用程序状态的优点为:

  • 实现简单   应用程序状态易于使用,为 ASP 开发人员所熟悉,并且与其他 .NET Framework 类一致。

  • **应用程序范围   **由于应用程序状态可供应用程序中的所有页来访问,因此在应用程序状态中存储信息可能意味着仅保留信息的一个副本(例如,相对于在会话状态或在单独页中保存信息的多个副本)。

使用应用程序状态的缺点为:

  • 应用程序范围   应用程序状态的范围可能也是一项缺点。在应用程序状态中存储的变量仅对于该应用程序正在其中运行的特定进程而言是全局的,并且每一应用程序进程可能具有不同的值。因此,不能依赖应用程序状态来存储唯一值或更新 Web 场和 Web 园服务器配置中的全局计数器。

  • 数据持续性有限   因为在应用程序状态中存储的全局数据是易失的,所以如果包含这些数据的 Web 服务器进程被损坏(如因服务器崩溃、升级或关闭而损坏),将丢失这些数据。

  • 资源要求   应用程序状态需要服务器内存,这可能会影响服务器的性能以及应用程序的可伸缩性。

应用程序状态的精心设计和实现可以提高 Web 应用程序性能。例如,如果将常用的、相关的静态数据集放置到应用程序状态中,则可以通过减少对数据库的数据请求总数来提高站点性能。但是,这里存在一种性能平衡。当服务器负载增加时,包含大块信息的应用程序状态变量就会降低 Web 服务器的性能。在移除或替换值之前,将不释放在应用程序状态中存储的变量所占用的内存。因此,最好只将应用程序状态变量用于更改不频繁的小型数据集。有关更多信息,请参见性能概述

会话状态

ASP.NET 提供了一种会话状态,该会话状态可作为 HttpSessionState 类或存储会话特定信息(仅在该会话中可见)的方法来使用。ASP.NET 会话状态将一个有限时间窗口内来自同一浏览器的请求标识为一个会话,并在该会话持续期间保留变量的值。有关更多信息,请参见 ASP.NET 状态管理概述ASP.NET 会话状态概述

可以在会话状态中存储会话特定的值和对象,该会话状态对象将由服务器来进行管理并可用于浏览器或客户端设备。存储在会话状态变量中的理想数据是特定于单独会话的短期的、敏感的数据。

使用会话状态的优点为:

  • 实现简单   会话状态功能易于使用,为 ASP 开发人员所熟悉,并且与其他 .NET Framework 类一致。

  • 会话特定的事件   会话管理事件可以由应用程序引发和使用。

  • 数据持久性   放置于会话状态变量中的数据可以经受得住 Internet 信息服务 (IIS) 重新启动和辅助进程重新启动,而不丢失会话数据,这是因为这些数据存储在另一个进程空间中。此外,会话状态数据可跨多进程保持(例如在 Web 场或 Web 园中)。

  • 平台可伸缩性   会话状态可在多计算机和多进程配置中使用,因而优化了可伸缩性方案。

  • 无需 Cookie 支持   尽管会话状态最常见的用途是与 Cookie 一起向 Web 应用程序提供用户标识功能,但会话状态可用于不支持 HTTP Cookie 的浏览器。但是,使用无 Cookie 的会话状态需要将会话标识符放置在查询字符串中(同样会遇到本主题在查询字符串一节中陈述的安全问题)。有关使用无 Cookie 会话状态的更多信息,请参见 管理 ASP.NET 网站

  • 可扩展性   您可通过编写自己的会话状态提供程序自定义和扩展会话状态。然后可以通过多种数据存储机制(例如数据库、XML 文件甚至 Web 服务)将会话状态数据以自定义数据格式存储。有关更多信息,请参见实现会话状态存储提供程序

使用会话状态的缺点为:

  • 性能注意事项   会话状态变量在被移除或替换前保留在内存中,因而可能降低服务器性能。如果会话状态变量包含诸如大型数据集之类的信息块,则可能会因服务器负荷的增加影响 Web 服务器的性能。

配置文件属性

ASP.NET 提供了一个称为配置文件属性的功能,可让您存储特定于用户的数据。除了当用户的会话过期时配置文件数据不丢失这点与会话状态不同外,它与会话状态类似。配置文件属性功能使用 ASP.NET 配置文件,ASP.NET 配置文件以固定的格式存储并与单个用户相关联。ASP.NET 配置文件可让您轻松地管理用户信息,而无需创建和维护自己的数据库。此外,配置文件使用了一个强类型 API,您可以在应用程序中的任何位置访问该 API,从而使用用户信息。您可以在配置文件中存储任何类型的对象。ASP.NET 配置文件功能提供了一个通用存储系统,使您能够定义和维护几乎任何类型的数据,同时仍可用类型安全的方式使用数据。有关更多信息,请参见 ASP.NET 配置文件属性概述

使用配置文件属性的优点为:

  • 数据持久性   放置在配置文件属性中的数据在 IIS 和辅助进程重新启动过程中得以保留而不会丢失数据,因为数据存储在一个外部机制中。此外,配置文件属性可跨多进程保持(例如在 Web 场或 Web 园中)。

  • 平台可伸缩性   配置文件属性可在多计算机和多进程配置中使用,因而优化了可伸缩性方案。

  • 可扩展性   为了使用配置文件属性,您必须对配置文件提供程序进行配置。ASP.NET 提供了一个 SqlProfileProvider 类,使您可以将配置文件数据存储在 SQL 数据库中,但您也可以创建自己的配置文件提供程序类将配置文件数据按自定义格式存储到自定义存储机制中,例如 XML 文件甚至 Web 服务。有关更多信息,请参见 ASP.NET 配置文件提供程序实现配置文件提供程序

使用配置文件属性的缺点为:

  • 性能注意事项   配置文件属性通常比使用会话状态慢,因为前者将数据持久保存到数据存储设备而非内存中。

  • 额外的配置要求   与会话状态不同,配置文件属性功能需要使用相当数量的配置。若要使用配置文件属性,您不仅要对配置文件提供程序进行配置,还要预先配置您想要存储的所有配置文件属性。有关更多信息,请参见 ASP.NET 配置文件属性概述定义 ASP.NET 配置文件属性

  • **数据维护   **配置文件属性需要一定的维护。因为配置文件数据持久保存到存储设备中,所以必须确保在数据陈旧时,应用程序调用由配置文件提供程序提供的相应清理机制。

数据库支持

在某些情况中,您可能希望使用数据库支持来维护网站上的状态。通常,数据库支持与 Cookie 或会话状态结合在一起使用。例如,对于电子商务网站,普遍使用关系数据库维护状态信息,其原因是:

  • 安全性

  • 个性化

  • 一致性

  • 数据挖掘

下面是支持 Cookie 的数据库网站的常见功能:

  • 安全性   访问者将帐户名称和密码键入到站点登录页中。站点结构通过登录值查询数据库以确定该用户是否有权使用您的站点。如果数据库确认该用户信息有效,网站将把包含该用户的唯一 ID 的有效 Cookie 分发到客户端计算机上。站点授予该用户访问权限。

  • 个性化   通过站点中存储的安全性信息,您的站点能够借助读取客户端计算机上的 Cookie 来区分站点上的每一用户。通常,站点在数据库中具有信息,描述用户的首选项(由唯一 ID 标识)。此关系通称作个性化。站点可以使用在 Cookie 中包含的唯一 ID 获知用户的首选项,然后向用户提供与用户的特定愿望相关并在一段时间内对用户首选项作出反应的内容和信息。

  • 一致性   如果您已创建了一个商业网站,您可能想要在站点上保留所购买的物品和服务的交易记录。这些信息能够可靠地保存在您的数据库中并通过用户的唯一 ID 来引用。它可用于确定购买交易是否完成,还可确定如果购买交易失败所应采取的操作步骤。这些信息还可用于通知用户使用您的站点所下的订单的状态。

  • 数据挖掘   有关站点使用、访问者或产品交易的信息能够可靠地存储在数据库中。例如,业务发展部门可能希望使用从该站点收集的这些数据确定下一年的产品线或分销策略。市场营销部门可能希望查看有关您的站点的用户的人口统计信息。设计和支持部门可能希望查看交易并记下购买过程可以改进的区域。诸如 Microsoft SQL Server 之类的大多数企业级关系数据库提供了可适用于大多数数据挖掘项目的可扩展工具集。

在上述方案中通过将网站设计为在每一一般性阶段使用唯一 ID 重复查询该数据库,该站点对状态进行维护。在此方法中,用户感受到站点正记住和响应其本人。

使用数据库维护状态的优点为:

  • 安全性   访问数据库需要严格的身份验证和授权。

  • 存储容量   可以根据需要在数据库中存储尽可能多的信息。

  • 数据持久性   可以根据需要在尽可能长的时间内存储数据库信息,这些信息不受 Web 服务器可用性的影响。

  • 可靠性和数据完整性   数据库包括多种用于维护有效数据的功能,其中包括触发器和引用完整性、事务等。通过在数据库中(而不是在会话状态等对象中)保存有关事务的信息,可以更为方便地从错误恢复。

  • 可访问性   存储在数据库中的数据可供众多的信息处理工具访问。

  • 广泛的支持   有大量数据库工具可供使用,并且有许多自定义配置可供使用。

使用数据库维护状态的缺点为:

  • 复杂性   使用数据库支持状态管理需要更复杂的硬件和软件配置。

  • 性能注意事项   不佳的关系数据模型结构可能导致可伸缩性问题。此外,对数据库执行过多的查询可能会影响服务器性能。

服务器端方法状态管理摘要

下表列出了 ASP.NET 可用的服务器端状态管理选项,并提供了有关何时使用每种选项的建议。

状态管理选项

使用建议

应用程序状态

可在以下情况下使用:存储由多个用户使用且更改不频繁的全局信息,而且不存在安全性问题。不要在应用程序状态中存储大量的信息。

会话状态

可在以下情况下使用:存储特定于单独会话的短期信息,并且需要较高的安全性。不要在会话状态中存储大量的信息。需要注意,将为应用程序中每一会话的生存期创建并维护会话状态对象。在支持许多用户的应用程序中,这可能会占用大量服务器资源并影响可缩放性。

配置文件属性

可在以下情况下使用:存储需要在用户会话过期后保留、并在对应用程序的后续访问中需要再次检索的特定于用户的信息。

数据库支持

可在以下情况下使用:存储大量信息,管理交易,或者信息必须可以经受得住应用程序和会话重新启动。数据挖掘十分重要,并且需要较高的安全性。

请参见

概念

ASP.NET 状态管理概述

ASP.NET Cookie 概述

ASP.NET 配置文件属性概述

ASP.NET 会话状态概述

ASP.NET 应用程序状态概述

其他资源

ASP.NET 状态管理的新增功能