ASP.NET 中的状态管理:你需要知道的一切






4.84/5 (20投票s)
本文概述了 ASP.NET 中各种状态管理技术。
引言
我们都知道 Web 应用程序使用 超文本传输协议 (HTTP)
进行通信。HTTP 协议基于 请求/响应
模式,并且本质上是无状态的。它不会保留回发之间的状态。
简单来说,这意味着当 客户端
从 Web 服务器
请求某项内容时,Web 服务器会响应客户端的请求并返回适当的响应。之后,它会清理用于响应该请求的资源。它不会保留请求的任何信息,并且与请求相关的所有信息都会丢失。
因此,每次 Web 服务器收到请求时,都会创建一个新的请求实例。这导致了 Web 应用程序的无状态性,并且客户端和服务器之间没有持久连接。为了克服这一限制,ASP.NET 提供了各种状态管理技术来在往返过程中保留数据。在本文中,我们将学习这些状态管理技术。
入门
在开始讨论状态管理技术之前,我将向您展示一个简单的演示,以帮助您理解 Web 应用程序无状态的含义。在此演示中,我使用了两个文本框(一个来自简单的 HTML 控件
,另一个来自 ASP.NET 服务器控件
)和一个按钮。我将在这些文本框中输入一些值并将这些值提交给 Web 服务器。让我们看看之后这些值会发生什么。
我正在使用新推出的免费 Visual Studio Community 2013
进行演示。如果您在安装和设置 Visual Studio Community 2013 方面需要任何帮助,请访问此 链接
。
打开 Visual Studio,创建一个空的 Web 应用程序,并将其命名为“StateManagementDemo
”。
默认情况下,对于空 Web 应用程序,Visual Studio 只会提供 web.config
文件。向项目中添加一个新的 Web 窗体,并将其命名为 Demo.aspx
。
我相信大家都熟悉 ASP.NET 中的 HTML 控件
和 服务器控件
。在此处阅读以了解更多信息
。在 Demo.aspx
中,添加两个文本框,一个来自简单的 HTML 控件,另一个来自服务器控件,并添加一个按钮控件。现在,构建项目并运行应用程序。
系统会显示一个演示页面,其中有两个空的文本框和一个提交按钮。让我们在这些框中输入一些值,然后单击“提交”按钮。
提交值后,页面会回发到 Web 服务器,结果如下:
这里发生的情况是,在往返服务器的过程中,普通 HTML 文本框的值丢失了,而服务器控件文本框的值得到了保留。HTML 文本框显示了基本 HTML 控件的无状态性,而服务器控件文本框显示了 ASP.NET 提供的用于处理 HTML 无状态性的服务器控件的优势。
那么,为什么服务器控件的值会被保留而 HTML 控件的值不会呢?对我来说,这似乎是个谜,我喜欢解决谜题(虽然不像尼古拉斯·凯奇那样)。所以,让我们弄清楚究竟发生了什么。
为什么 ASP.NET 控件会保留其状态?
前面的示例显示了一个有趣的结果,因为我们传递给服务器控件的值在往返过程中被保留了,而 HTML 控件中的值在到达服务器后立即被销毁。如果我们深入挖掘真正发生的事情,技术解释是服务器控件中一个状态管理技术的隐式使用,该技术有助于保留状态,而该技术是 视图状态
。确切地说,是服务器控件实现的 IPostBackDataHandler
接口,用于在往返过程中保留状态,这使得它们对我们来说更有趣和更重要。但是,视图状态并不是 ASP.NET 为状态管理提供的唯一技术。还有各种其他技术;事实上,整个状态管理分为两大类。我不会在本文中讨论所有状态管理技术,只讨论常用的技术。
客户端状态管理
客户端状态管理技术用于使用客户端选项存储数据,而无需使用服务器资源。此技术将数据存储在客户端的浏览器中,而不是使用服务器资源。此技术的主要优点是更好的可伸缩性。但是,由于数据存储在客户端,因此安全性较低,不能用于存储任何敏感数据。ASP.NET 提供了以下选项来实现客户端状态管理:
- 视图状态
- Cookie
- 查询字符串
- 控制状态
- 隐藏字段
服务器端状态管理
服务器端状态管理在存储数据方面提供了比客户端更高的安全性。数据保存在服务器上,因此不会传递给客户端。但是,此技术会消耗更多服务器资源,可以明智地使用。ASP.NET 提供了以下选项来实现服务器端状态管理:
- 会话状态
- 应用程序状态
状态管理技术
为了更好地理解这些技术,让我们考虑一个开发人员的虚构网站的场景,“Developer's Cafe”
。该网站包含两个页面:登录
和 仪表板
。登录页面包含两个用于用户名和密码的文本框,一个用于提交值的按钮,以及三个标签控件,一个用于向用户显示欢迎消息,另一个用于显示用户在凭据错误的情况下登录失败的次数,最后一个用于显示在线访问者的数量。仪表板页面在成功登录后显示用户名,并提供一个注销按钮以结束用户的当前会话。
我们将看到各种状态管理技术如何适用于此场景。应用程序的完整源代码可以从我的GitHub 帐户
下载。
注意:请注意,本文提出的真实场景仅用于教育目的,以便读者能够理解这些技术。它不能直接在实际项目中实现。在使用状态管理技术之前,需要考虑几个选择标准,因为每种技术都有其自身的优点和缺点。
视图状态
定义
视图状态是一种页面级状态管理技术,用于在同一页面的多个请求之间存储信息。视图状态是 ASP.NET 服务器控件在往返过程中保留页面和控件属性值的默认机制。
视图状态使用页面内存来存储信息,并通过在同一页面上使用名为 _VIEWSTATE 的隐藏表单字段来实现。存储在视图状态中的项存在于当前页面的生命周期内。对于 Web 控件和整个页面,视图状态默认是启用的。但是,我们可以通过将 EnableViewState 属性更改为 False
来禁用视图状态的数据存储。
优点
- 视图状态是 ASP.NET 服务器控件在往返过程中保留状态的默认机制。
- 它是一种 State Bag 集合类的字典类型,可用于存储任何类型的数据。
- 它是存储在单个网页中用于多次回发的数据的理想位置。
缺点
- 视图状态的主要缺点是信息仅为当前页面存储。一旦用户从当前页面重定向到另一页或意外关闭页面,视图状态就会被销毁,并且无法传输到重定向的页面。
- 默认情况下,视图状态中存储的信息未加密,任何人都可以轻松篡改。因此,不能用于存储任何敏感数据。但是,我们可以使用
EnableViewStateMac
属性加密视图状态。 - 由于视图状态会导致页面大小增加并引起开销问题,因此不能用于存储大量数据。
真实场景
在我们的 登录页面
中,假设我们需要计算 用户
在密码错误的情况下登录尝试的次数。如果用户输入错误的密码,它将再次重定向到同一个 登录页面
。视图状态机制非常适合这种情况,我们可以使用它来计算用户登录到网站时尝试错误的次数。视图状态对象是一个字典类型,允许我们在同一页面的多个请求中保存和恢复任何数据。请注意,我们无法将视图状态数据从一个页面传递到另一个页面。
下图显示了在 登录页面
中使用视图状态。如果用户输入正确的凭据,它将重定向到下一页。但是,如果用户输入错误的密码,它将再次被抛回到同一个 登录页面
,并且其登录尝试次数会增加一。我们正在计算用户尝试登录到网站的错误次数。
Cookie
定义
Cookie 是一种客户端状态管理技术,通常用于提供个性化、跟踪使用情况或存储用户信息。Cookie 是一个小的文本文件,存储在客户端的计算机上或客户端浏览器会话的内存中。Cookie 的最大尺寸为 4096 字节
或 4KB
,通常允许在客户端计算机上最多存储 300 个 Cookie
,每个服务器或域允许 20 个 Cookie
。
Cookie 有两种类型:
持久性 Cookie:
此类型的 Cookie 永久存储在客户端计算机的硬盘驱动器上。持久性 Cookie 有一个到期日期,如果我们不提供任何特定日期,它将被视为非持久性或瞬时 Cookie。
- 非持久性/瞬时 Cookie: 此类型的 Cookie 临时存储在客户端浏览器的内存中。只有在浏览器运行时才可用。
优点
- 它非常简单易用。
- 创建 Cookie 只需占用少量内存。
缺点
- 用户可以通过调整浏览器设置轻松禁用 Cookie。
- 删除 Cookie 的唯一方法是手动删除它,或者用一个已过期的 Cookie 替换它。
- Cookie 存储在客户端计算机上,因此不能用于存储任何敏感数据。
真实场景
在我们 登录页面
的示例中,假设我们需要跟踪 用户
的访问历史;也就是说,我们需要检查 用户
是第一次登录网站还是常规访客。这种情况可以使用 Cookie
轻松完成,我们可以利用持久性 Cookie 来识别用户。
下图显示了在用户计算机上实现持久性 Cookie。如果用户第一次访问网页,则在其计算机上创建一个 Cookie,如果用户是第二次访问,则检索相同的 Cookie。这有助于我们检查用户状态。我们将持久性 Cookie 的 Cookie 有效期设置为 1 年,以便在客户端计算机上可用。图像显示了用户第一次和第二次的访问历史。请注意,两次访问的欢迎消息都已更改。
查询字符串
定义
查询字符串(或 HTTP 查询字符串)是附加到 URL 末尾的信息。它通常用于通过 URL 将数据从一个页面传递到另一个页面。在 URL 中,查询字符串跟随分隔符,通常是问号 (?)
。请考虑以下 URL:
http://www.developerscafe.com/Dashboard.aspx?username=admin
优点
- 它提供了一种将信息从一个页面传递到另一个页面的简便方法。
- 几乎所有浏览器和客户端设备都支持查询字符串。
缺点
- 查询字符串中的信息通过浏览器的用户界面对用户可见,因此不能用于敏感数据。
- 在几乎所有常用浏览器中,URL 的最大长度为 2083 个字符。因此,我们不能将大量信息作为查询字符串附加到 URL。
真实场景
在 登录页面
中,用户输入凭据并准备登录网站。如果凭据正确,它应该重定向到另一个页面,例如 仪表板
。现在,我们想将用户的一些信息从登录页面传输到仪表板页面,例如用户名。这种情况可以使用查询字符串轻松完成。
例如,我们想在仪表板页面上显示用户登录时输入的用户名。我们可以使用查询字符串将用户名附加到 URL,并在仪表板页面上检索它。
会话状态
定义
会话状态是一种服务器端状态管理技术,允许我们为特定用户存储数据。它用于在有限的时间内存储值。为应用程序的每个会话创建一个唯一的会话 ID。会话 ID 通过 Cookie 或通过修改后的 URL 来维护。
会话状态存储在 HttpSessionState
类的实例中。存储在会话状态中的值的范围仅限于特定用户,不能在网站的多个用户之间共享。会话状态支持以下存储数据模式。
- InProc 模式
- State Server 模式
- SQL Server 模式
- 自定义模式
- Off 模式
优点
- 会话状态的范围仅限于特定用户。
- 它提供了一种安全的方式来存储应用程序所有页面中的数据。
- 它也可以与不支持 Cookie 的浏览器一起使用。
缺点
- 它使用服务器内存存储数据,如果处理不当,可能会对性能产生不利影响。
真实场景
在查询字符串示例中,我们使用查询字符串将用户信息从 登录页面
传输到 仪表板页面
。您已经注意到用户名已附加到 URL,并且很容易被篡改。这不是传输敏感数据的推荐方法。要传输敏感数据,我们需要一种安全的方法,这时会话状态就派上用场了。会话变量通过服务器端状态管理提供了一种更好的方法来处理相同的情况。
下图显示了使用会话状态的相同场景。请注意,URL 中没有可被篡改的数据附加。
应用程序状态
定义
应用程序状态用于存储需要为整个应用程序提供的数据。应用程序状态存储在服务器的内存中。与仅限于单个用户会话的会话状态不同,应用程序状态适用于所有用户和会话。存储在应用程序状态中的数据会一直保留,直到应用程序运行或 Web 服务器重启为止,当您的应用程序重启或 Web 服务器重启时,数据将丢失。
应用程序状态存储在 HttpApplicationState
类的实例中。此类是命名对象集合,这意味着它应作为键/值对存储任何类型的数据。
优点
- 应用程序状态的范围是全局的。我们可以存储可在整个应用程序中访问的数据。
- 它没有任何默认到期时间。
缺点
- 应用程序状态需要服务器资源来存储数据。如果处理不当,这可能导致可伸缩性问题。
- 应用程序状态不是线程安全的,因此我们需要实现锁。
- 在应用程序失败或重启的情况下,所有存储的数据都会丢失。
真实场景
假设我们的网站需要一个计数器来跟踪在线用户的数量。为了实现在线计数器,我们可以使用可供整个应用程序全局访问的应用程序状态,并将数据存储在服务器端,直到网站在服务器上运行或直到服务器重启。
下图显示了仪表板页面上的计数器,该计数器显示活动用户数量。我们使用 Global.asax
来实现在线计数器。
结论
应用程序的完整源代码可在GitHub 上找到。希望本文能帮助您理解 ASP.NET 的各种状态管理技术。您的反馈和建设性的批评始终受到赞赏,请继续提出。在此之前,尝试在宇宙中留下痕迹!