原文地址http://msdn2.microsoft.com/en-us/library/ms972976.aspx
翻译:Jupiter
日期:2008-3-1
Scott Mitchell
4GuysFromRolla.com
May 2004
Applies to:
Microsoft® ASP.NET
Microsoft® Visual Studio® .NET
Summary: Scott Mitchell looks at the benefits of and confusion around ViewState in Microsoft® ASP.NET. In addition, he shows you how you can interpret (and protect) the data stored in ViewState. (25 printed pages)
Click here to download the code sample for this article.
内容:
介绍
ASP.NET页面生命周期
View State的角色
View State和动态添加的控件
ViewState属性
跟踪View State
将信息存储到页面的ViewState属性中
View State的成本
禁止View State
指定将View State持久化到哪里
解析View State
View State和隐含的安全问题
结论
微软的ASP.NET view state,本质上来说,是一种使Web表单在回传时能够维护表单自身状态的技术。作为一个培训者和咨询师,根据我的经验,视图状态在ASP.NET开发者中间引起了巨大的困惑。如果没有深入掌握什么是视图状态,它是如何工作的,那么当创建自定义服务器控件或者使用一些高级的页面技术时会很麻烦。专注于创建低带宽的,流畅页面的Web设计者也经常对Web设计者非常困惑。页面的Web设计者默认情况下放在一个名称为_VIEWSTATE的隐藏表单域中。这个隐藏表单域很容易变得很大,甚至十几K字节。_VIEWSTATE隐藏表单域不仅会使下载变慢,而且每当用户回传web页面时,这个隐藏域的内容也会随着HTTP请求回传到服务器端,因此也延长了请求时间。
这篇文章主要目的是深入的探讨ASP.NET视图状态。我们将看到视图状态是如何存储,如何序列化隐藏表单域以及如何反系列化的。我们也将讨论如何减少视图状态所占用的带宽。
注意 这篇文章主要针对ASP.NET页面开发者,而不是服务器控件开发者。因此这篇文章不介绍控件开发者如何保存状态。关于这个问题的深入讨论,请参考图书Developing Microsoft ASP.NET Server Controls and Components.
在开始我们对视图状态的探讨之前,首先快速的讨论一下ASP.NET页面生命周期。也就是说,当一个ASP.NET页面请求到来时,到底发生了什么?我们将在下一个部分中继续这个讨论。
每次当一个对ASP.NET web页面的请求到达web服务器时,web服务器做的第一件事情就是将请求转交给ASP.NET引擎。ASP.NET引擎于是携带请求通过一个由许多阶段构成的流水线,包括确认对ASP.NET web页面的文件访问权限,再现用户的会话状态,等等。在流水线的最后,实例化对应于请求的ASP.NET web页面类,并调用ProcessRequest()方法(见图1)。
图1 ASP.NET页面处理
ASP.NET页面的生命周期起始于对ProcessRequest()方法的调用。这个方法首先初始化页面的控件体系结构。然后,页面和他的服务器控件一起经历各种阶段,它们对ASP.NET web页面的执行都非常重要。这些步骤包括管理视图状态,处理回传事件,和呈现页面的HTML标记。图2提供了ASP.NET 页面生命周期的图形表示。生命周期终止于将Web页面的HTML标记提交给Web服务器,然后它将其发送回请求页面的客户端。
Note A detailed discussion of the steps leading up to the ASP.NET page life cycle is beyond the scope of this article. For more information read Michele Leroux-Bustamante's Inside IIS & ASP.NET. For a more detailed look at HTTP handlers, which are the endpoints of the ASP.NET pipeline, check out my previous article on HTTP Handlers.
重要的是认识到每当请求ASP.NET Web页面时,它都经历这些相同的页面生命周期阶段(如图2所示)。
图2 页面生命周期中的事件
阶段0-初始化
ASP.NET页面的生命周期始于代表所请求的ASP.NET Web页面的类的实例化,但是这个类是如何创建的?它又存储在哪里?
ASP.NET Web页面,是由HTML部分和代码部分组成的,HTML部分包含了HTML标记和Web控件语法。ASP.NET引擎将HTML部分从它的文本表示转换为一系列的编程创建的Web控件。
当第一次访问一个ASP.NET Web页面时,ASP.NET引擎自动生成一个类。如果你所创建的ASP.NET Web页面使用了code-behind技术,这个自动生成的类派生自与页面相关的code-behind类(注意code-behind类必须直接或间接派生自System.Web.UI.Page);如果你使用一个内联的,服务器端块创建你的页面,那么这个类直接派生自System.Web.UI.Page。在任何一种情况下,这个自动生成的类,和这个类的一个编译后的实例存储在WINDOWS/Microsoft.NET/Framework/version/Temporary ASP.NET文件夹,因此不需要每次页面请求都重新生成它。
这个自动生成的类的目的是编程创建页面的控件体系。也就是说,这个类负责编程创建在页面的HTML部分指定的Web控件。这是通过将Web控件语法-
所有的ASP.NET服务器控件都可以有一个父控件和一些数目的子控件。System.Web.UI.Page类派生自基控件类(System.Web.UI.Control),因此也可以有一系列的子控件。声明在ASP.NET Web页面的HTML部分的顶层控件是自动生成的Page类的直接孩子。Web控件也可以彼此嵌套。例如,大多数ASP.NET Web页面只包含一个服务器端的Web Form和位于Web Form内的多个Web控件。Web Form是一个HTML控件(System.Web.UI.HtmlControls.HtmlForm)。那些位于Web Form内部的Web控件是Web Form的孩子。
由于服务器控件可以有孩子,他们的孩子又可以有孩子,等等,控件和它的子孙形成了控件树。这个控件树称为控件体系结构。ASP.NET Web页面控件体系结构的根是派生自Page的类,它是由ASP.NET引擎自动生成的。
最后几段看起来可能有点困惑,这是因为这不是一个容易探讨的问题。为了清除潜在的困惑,让我们来看一个例子。试想你的ASP.NET Web页面拥有下面的HTML部分:
当首次访问此页面时,将自动生成一个类,它包含编程创建控件体系结构的代码。这个控件体系结构如图3所示。
图3。 示例页面的控件体系结构
这个控件体系结构会被转化为类似下面的代码:
注意 上面的C#代码不是由ASP.NET引擎自动生成的精确代码。如果想要查看全部的自动生成的代码,转到WINDOWS/Microsoft.NET/Framework/Version/Temporary ASP.NET Files文件夹,打开其中的.cs或.vb文件。
一个值得注意的事情是,当控件体系结构被创建时,那些显式设置在Web控件声明语法中的属性是在代码中被赋予的。(例如,Button控件有一个Text属性在声明语法中被设置为”Submit!”-在自动生成的类中对应于Button1.Text=”Submit!”)
阶段1-初始化
在创建控件体系结构后,Page和其中所有的控件,进入初始化阶段。这个阶段的标志是Page和控件触发它们的Init事件。此刻,控件体系结构已经被创建完毕,显式设置在Web控件声明语法中的属性也已经被赋值。
我们将在这篇文章的后面更详细的探讨初始化阶段。视图状态非常重要的两个原因;一是服务器控件直到初始化阶段的末尾才会跟踪视图状态。二是当添加需要利用视图状态的动态控件时,这些控件需要在Page的Init事件中被添加而不是在Load事件中,我们稍后就会看到。
阶段2-装载视图状态
仅当页面被回传时才会装载视图状态。在这个阶段,上次访问页面访问时被保存的视图状态数据被装载并且递归的传染到Page的控件体系结构。就是在这个阶段对视图状态进行校验。正如我们稍后所讨论的,视图状态可能由于各种原因而变得无效,例如视图状态tampering,在控件体系结构的中间插入动态控件。
未完待续