首页 > 代码库 > ASP.NET状态管理详解,让你明明白白
ASP.NET状态管理详解,让你明明白白
开发WinFrom的程序员可能不会在意维护应用程序的状态,因为WinFrom本身就在客户端运行,可以直接在内存中维护其应用程序状态。但ASP.NET应用程序在服务器端运行,客户端使用无状态的http协议对ASP.NET应用程序发出请求,ASP.NET应用程序响应用户请求,向客户端发送请求的HTML代码,服务器并不会维护任何客户端状态。考虑一个有成千上万并发用户的服务器,如果为每一个用户都维护状态的话会耗费非常多的资源。
由于使用无状态的http协议作为web应用程序的通信协议,当客户端每次请求页面时,ASP.NET服务器都会重新生成一个网页的新实例。这意味着客户端用户在浏览器中的一些状态或者是一些修改都将丢失。
记得在使用ASP的时候,为了保存每个文本框的值,在数据提交前使用了大量的Session变量来保存每个文本框的值,并在页面重新生成后将这些会话变量中的值一一赋给每个文本框,这是一种相当费时费力的工作。
而ASP.NET提供了状态管理的技术视图状态技术会自动保存及分配每一个控件的状态,此外提供了一种控件状态技术。
视图状态(ViewState):使用一个或多个隐藏域来保存控件的数据。
当然我们也可以使用其保存自己的状态数据,方法是使用ViewState这个内置对象,ViewState[key]=value;。这个对象是字典类型。当要取其值的时候需要进行类型转换,int i=(int)ViewState[key];因为值在ViewState里的存储类型是Object。存储在ViewState里的数据可以是简单的数据类型也可以是自定义的类型,但自定义的类型必须支持序列化(也就是在声明类的时候要在类上面写上[Serializable]级别)。不过要弄清楚的是用ViewState保存数据仅限于当前用户当前页面,并不能跨页面传递信息。由于其默认可以保存大部分控件的状态,所以其在服务器端与客户端来回传递时将占用大量的网络带宽,并且由于其是存储在客户端的,所以会占用过多的客户端的内存从而影响执行效率。所以对于有些不需要保存状态在ViewState里的控件我们可以通过其EnableViewState属性来禁用其视图状态。也可以通过<%@ Page EnableViewState="false">来禁用该页面的所有视图状态。视图状态是通过ASP.NET引擎将其保存在一个隐藏域HiddenField里,<input type="hidden" name="_VIEWSTATE" id="_VIEWSTATE" value="http://www.mamicode.com/这些状态以键/值对集合的形式保存并且以Base64编码格式编码">。由于Base64编码的字符串可以由很多工具解码(如ViewStateDecoder),所以对于敏感的数据保存在视图状态里将很危险。如果非要将敏感信息存放在视图状态里,可以在<%@ Page
ViewStateEncryptionMode="Always">或在Webconfig的pages节点里设置ViewStateEncryptionMode的值。也可以在后置代码里Page.RegisterRequiresViewStateEncryption();但前提是在@Page和pages节点里ViewStateEncryptionMode没有设置为Never。这时会多一个隐藏域名字为__VIEWSTATEENCRYPTED。
控件状态(ControlState):当开发自定义控件时,保存控件的状态数据。
为了让控件正常工作,有时需要存储控件状态数据。例如,如果编写了一个自定义控件,其中具有显示不同信息的不同选项卡,为使该控件如预期一样工作,控件需要知道在往返过程中选择的是哪个选项卡。ViewState 属性可用于此目的,但开发人员可能在页级别关闭了视图状态,从而有效地中断控件。为解决此问题,ASP.NET 页框架在 ASP.NET 2.0 版中公开了一种称为控件状态的新功能。ControlState 属性允许保持特定于控件的属性信息,不像 ViewState 属性一样可以关闭。若要使用控件状态,控件必须在初始化过程中调用 RegisterRequiresControlState 方法,然后重写 SaveControlState 和 LoadControlState 方法。
默认情况下,ASP.NET 页框架将控件状态存储在页的一个隐藏元素中,视图状态也同样存储在此隐藏元素中。即使禁用视图状态,或是使用 Session 管理状态时,页面中的控件状态仍会传输至客户端,然后返回到服务器。在回发时,ASP.NET 会对隐藏元素的内容进行反序列化,并将控件状态加载到每个注册过控件状态的控件中。
从MSDN上的一系列的技术参考来看,ControlState应该是主要在自定义控件上使用,“ASP.NET 页框架提供了 ControlState 属性作为在服务器往返过程中存储自定义控件数据的方法”,这是MSDN上的原句,ASP.NET2.0只是为ControlState提供了一个基础,当 ControlState是一个自定义的状态保持机制,也就是说保持状态的机制需要你开发人员自己去完成,而不像ViewState,它有自己默认的状态保持机制。在自定义控件使用ControlState也许才是微软本意了,为的就避免在页面级别禁用掉ViewState后,自定义控件还能正常运行。当然这里的意思就是,某些控件的正确运行是依赖于它的状态信息的,在ASP.NET1.1中,如果禁用了ViewState,这样的控件就无法正确运行了。但引入了ControlState后就不同了,因为ControlState是禁用不掉的。
所以微软才提醒开发人员“请仅对那些在回发过程中对控件至关重要的少量关键数据使用控件状态,而不要将控件状态作为视图状态的备用选项使用”。明确说出,ControlState和 ViewState完全是两个东西,虽然它们可以完成相同的任务,新推出的ControlState既不是用来替代ViewState也不是用来做 ViewState的替补。它的使命是弥补ViewState的所不能完成的任务,让开发人员开发出更加健壮的控件。例如说,开发的自定义控件某个状态是至关重要的,缺少它就自定义控件不能正常工作,那么ControlState就该上场了。而且ControlState是自定义的状态保持机制,也限制了 ControlState自由的使用,你不但要在OnInit 方法并调用 RegisterRequiresControlState 方法向页面注册,而且要重写SaveAdapterControlState(),LoadAdapterControlState(object state)两个方法自己去实现要保存什么,怎样保存。根据我现在的理解,如果你需要保存该控件的10种不同状态,那你就得一一保存,再一一加载上去。从这点也就看出了微软的初衷了,那不是很明显吗,如果不需要ControlState那就不使用它吧,否则怎么它什么都让我们开发人员去做呢?
有关链接:http://kendezhu.iteye.com/blog/810562的3和5
http://www.cnblogs.com/think-jerry/archive/2007/05/24/758240.html及其下一篇
补:cookies session application
Session
Session与ViewState类似,也可以保存任何标准数据类型和任何派生自object的类型的对象,使用方法也一样。但Session可以跨页面保存,同一个用户在不换浏览器的情况下跳转到其他页后仍然能通过Session得到前一个页面保存的数据。Session状态与ViewState不同,它是保存在服务器端的。ASP.NET会给每一个Session创建一个唯一的SessionID(120位标识符),这个SessionID将会以Cookie或Url的方式发送到客户端,这样服务器端就能根据客户端的SessionID来维护每个客户端的会话了(所以不管程序中是否使用Session["键"]=值在服务器端建立了会话,都会有SessionID发到客户端,只不过建立了会话,SessionID就有用武之地了,就可以用来维护每个客户端的会话了)。但当客户端用户关闭了浏览器,使用不同的浏览器,长时间没操作导致会话超时都会导致服务端会话状态丢失。会话状态默认是存储在服务器的内存里,这样做固然有效率上的优势,但会占用大量的服务器端内存,我们可以将其保存到数据库等其他地方,下面就来学习一下在webconfig中配置会话状态:
在webconfig的system.web节点下添加sessionState节点如下配置:
<system.web>
<sessionState
cookieless="UseCookies" cookieName="ASP.NET_sessionid"
mode="SQLServer" timeout="20"
sqlConnectionString="Data Source=.\sqlexpress;Integrated Security=SSPI"
sqlCommandTimeout="30">
</sessionState>
</system.web>
cookieless设置SessionID是用Cookie还是用Url发送到客户端,或是通过检测决定。cookieName设置保存SessionID的Cookie的名字。mode设置Session状态的保存方式,默认是InProc保存在服务器内存里,这里设置了保存在SQLServer数据库里。sqlConnectionString设置连接字符串。sqlCommandTimeout设置超时值。
设置完之后,在Visual Studio 2008命令提示符下输入:
aspnet_regsql.exe -S .\SQLEXPRESS -E -ssadd -S后面跟的是数据库服务器名称
添加后服务器里会多了一个数据库ASPState,要想移除该数据库,在提示符下输入:
aspnet_regsql.exe -S .\SQLEXPRESS -E -ssremove
但这时状态表位于tempdb数据库里,所以重启SQLServer的话会导致会话信息丢失,要输入:
aspnet_regsql.exe -S .\SQLEXPRESS -E -ssadd -sstype p
这样状态表就会出现在ASPState数据库里了,并且会话信息会持久保留。
如果要将状态数据保存在自己的数据库里,要输入:
aspnet_regsql.exe -S .\SQLEXPRESS -E -ssadd -sstype c -d 数据库名
然后在sessionState节点里修改属性:
allowCustomSqlDatabase="true" 允许使用自定义数据库
sqlConnectionString="Data Source=.\sqlexpress;Initial Catalog=tempdb;Integrated Security=SSPI" 链接字符串加数据库
相关链接:
http://www.cnblogs.com/shoru/archive/2010/02/19/1669395.html
http://www.cnblogs.com/flier/archive/2004/08/04/30226.html(一)
http://www.cnblogs.com/flier/archive/2004/08/07/30902.html(二)
Application
Application的用法与Session一样,并且也是保存在服务器端。但Application是一个全局对象,不仅局限于一个页面一个浏览器,它被所有用户所共有。而且其没有超时的概念,除非服务器关闭或重启。最常用的例子是网页计数器:
protected void Page_Load(object sender, EventArgs e) { int i=0; if (Application["PageCount"]!=null) { Application.Lock(); 加锁,防止多用户同时访问(并发访问) i = (int)Application["PageCount"]; i++; Application["PageCount"] = i; Application.UnLock(); 操作完后解锁 } else { Application["PageCount"] = 0; } Label1.Text = i.ToString(); }