第17章 ASP.NET状态管理
到目前为止,无论你在什么框架上开发Web应用程序,无论是ASP.NET还是JSP,无论你的开发框架多么先进与高级,它们都改变不了一个现实问题:HTTP协议是一种无状态的协议。
我们知道,每次将网页发送到服务器时,都会创建网页类的一个新实例。在传统的Web编程中,这通常意味着在每一次往返行程中,与该页及该页上的控件相关联的所有信息都会丢失。例如,如果用户将信息输入到文本框,该信息将在从浏览器或客户端设备到服务器的往返行程中丢失。
为了解决传统Web编程的这些固有的限制,ASP.NET提供了多项状态管理技术,可帮助你按页保留数据和在整个应用程序范围内保留数据。
17.1 ASP.NET状态管理概述
简单地讲,状态管理是对同一页或不同页的多个请求维护状态和页信息的过程。与所有基于HTTP的技术一样,Web窗体页是无状态的,这意味着它们不自动指示序列中的请求是否全部来自相同的客户端,或者单个浏览器实例是否一直在查看页或站点。此外,到服务器的每一往返过程都将销毁并重新创建页。因此,如果超出了单个页的生命周期,页信息将不存在。例如,在代码中声明一个DataSet数据集从数据库中获取记录,页面回发(也就是重新请求)后这个DataSet是空的,这就是为什么在ASP.NET应用程序中,甚至在一个页面中需要多次连接数据库获取记录。正是由于这个原因,状态管理对于Web编程来说非常重要。
ASP. NET支持多种状态管理技术以弥补HTTP无状态的不足。其中,主要包括如下技术:视图状态、控件状态、隐藏字段、Cookie、查询字符串、应用程序状态、会话状态与配置文件属性。
17.1.1 服务器端状态管理
在ASP.NET中,提供了应用程序状态、会话状态及配置文件属性三种状态管理技术来用于维护服务器上的状态信息。通过基于服务器的状态管理,为了保留状态,可以减少发送给客户端的信息量,但因此也会使用服务器上的高成本资源。其中:
1)应用程序状态。关于应用程序状态,在第1章已经做过阐述。ASP.NET允许使用应用程序状态来保存每个活动的Web应用程序的值。并且,它是一种全局存储机制,可以Web应用程序中的所有页面访问。因此,应用程序状态可用于存储需要在服务器往返行程之间及页请求之间维护的信息。
2)会话状态。会话状态可以保存每个活动的Web应用程序会话的值。它与应用程序状态非常相似,不同的只是会话状态的范围限于当前的浏览器会话。如果有不同的用户在使用你的应用程序,则每个用户会话都将有一个不同的会话状态。此外,如果同一用户在退出后又返回到应用程序,第二个用户会话的会话状态也会与第一个不同。
3)配置文件属性。与会话状态类似,配置文件属性功能可以让你存储特定于用户的数据。不同的是,在用户的会话过期时,配置文件数据不会丢失。配置文件属性功能使用ASP.NET配置文件,此配置文件以持久的格式存储,并与某个用户关联。
ASP. NET配置文件可让你轻松地管理用户信息,而无须创建和维护自己的数据库。此外,配置文件使用了一个强类型API,你可以在应用程序中的任何位置来访问该API,从而使用用户信息。当然,也可以在配置文件中存储任何类型的对象。ASP.NET配置文件功能提供了一个通用存储系统,使你能够定义和维护几乎任何类型的数据,同时仍可用类型安全的方式使用数据。
17.1.2 客户端状态管理
相对于服务器端状态管理,ASP.NET提供了视图状态、控件状态、隐藏域、Cookie和查询字符串五种状态管理技术,它们都可以以不同方式将数据存储到客户端上。其中:
1)视图状态。视图状态((VewState)是一项非常重要的技术,它能使得页面和页面中的控件在从服务器到客户端,再从客户端返回的往返过程中保持状态。这样就可以在Web这种无状态的环境之上创建一个有状态并持续执行的页面效果。即在处理页时,页和控件的当前状态会散列为一个字符串,并在页中保存为一个隐藏域或多个隐藏域。当将页回发到服务器时,页会在页初始化阶段分析视图状态字符串,并还原页中的属性信息。
2)控件状态。有时,为了让控件正常工作,需要按顺序存储控件状态数据。例如,如果编写了一个自定义控件,其中使用了不同的选项卡来显示不同的信息。为了让自定义控件按预期的方式工作,该控件需要知道在往返行程之间选择了哪个选项卡。当然,可以使用视图状态来实现这一目的,不过,开发人员可以在页级别关闭视图状态,从而使控件无法正常工作。
为了解决此问题,ASP.NET页框架在ASP.NET中公开了一项名为控件状态((CntrolState)的功能。它允许你保持特定于某个控件的属性信息,且不能像视图状态那样被关闭。下面的代码演示了如何在ControlState中保存和读取简单的字符串:
PageStatePersister.ControlState="易学C#";
Response.Write(PageStatePersister.ControlState.ToString());
3)隐藏域。对于隐藏域((HddenField),相信大家已经了解,前面的章节我们也做了详细的阐述。作为状态管理技术,ASP.NET允许你将信息存储在HiddenField控件中,此控件将呈现为一个标准的HTML隐藏域。隐藏域在浏览器中不以可见的形式呈现,但可以像对待标准控件一样设置其属性。当向服务器提交页时,隐藏域的内容将在HTTP窗体集合中随同其他控件的值一起发送。因此,可以将隐藏域看成是一个储存库,可以将希望直接存储在页中的任何特定于页的信息放置到其中。
为了在页处理期间能够使用隐藏域的值,必须使用HTTP POST命令提交相应的页。如果在使用隐藏域的同时,为了响应某个链接或HTTP GET命令而对页进行了相应处理,那么隐藏域将不可用。
4)Cookie。Cookie是一些少量的数据,这些数据可以存储在客户端文件系统的文本文件中,也可以存储在客户端浏览器会话的内存中。同时,Cookie可以是临时的(具有特定的过期时间和日期),也可以是永久的。
可以使用Cookie来存储有关特定客户端、会话或应用程序的信息。Cookie保存在客户端设备上,当浏览器请求某页时,客户端会将Cookie中的信息连同请求信息一起发送。当然,服务器也可以读取Cookie并提取它的值。
5)查询字符串。查询字符串是在页URL的结尾附加的信息。如下面的URL路径所示:
http://www.comesns.com/list.aspx?ID=100&class=3
在上面的URL路径中,查询字符串以问号(?)开始,并包含两个特性/值对:一个名为“ID”,另一个名为“class”。由此可见,利用查询字符串可以很容易地将信息从一页传送到另一页。因此,使用查询字符串具有如下优点:
❑不需要任何服务器资源,查询字符串包含在对特定URL的HTTP请求中。这里还需要说明的是,若要在页处理期间可以使用查询字符串的值,必须使用HTTP GET命令提交页。也就是说,如果为了响应HTTP POST命令而对页进行了相应处理,则不能利用查询字符串。
❑广泛的支持,几乎所有的浏览器和客户端设备均支持使用查询字符串传递值。
❑实现简单。ASP.NET完全支持查询字符串方法,其中包含了使用HttpRequest对象的Params属性读取查询字符串的方法。
当然,查询字符串也有一定的局限性:
❑潜在的安全性风险。用户可以通过浏览器用户界面直接看到查询字符串中的信息,并且可将此URL设置为书签或发送给别的用户,从而通过此URL传递查询字符串中的信息。
❑有限的容量。目前大多数浏览器和客户端设备会将URL的最大长度限制为2083个字符。