理解ASP.NET View State(1)

理解ASP.NET View State1

原文地址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 View State in Microsoft® ASP.NET. In addition, he shows you how you can interpret (and protect) the data stored in View State . (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页面生命周期

每次当一个对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);如果你使用一个内联的,服务器端<script>块创建你的页面,那么这个类直接派生自System.Web.UI.Page。在任何一种情况下,这个自动生成的类,和这个类的一个编译后的实例存储在WINDOWS/Microsoft.NET/Framework/version/Temporary ASP.NET文件夹,因此不需要每次页面请求都重新生成它。

这个自动生成的类的目的是编程创建页面的控件体系。也就是说,这个类负责编程创建在页面的HTML部分指定的Web控件。这是通过将Web控件语法-<asp:WebControlName Prop1="Value1" ... />翻译为编程语言来做到的。除了Web控件语法被转化合适的代码,出现在ASP.NET Web页面的HTML部分的HTML标记被翻译为Literal控件。

所有的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部分:

<html>
<body>
  <h1>Welcome to my Homepage!</h1>
  <form runat="server">
    What is your name?
    <asp:TextBox runat="server" ID="txtName"></asp:TextBox>
    <br />What is your gender?
    <asp:DropDownList runat="server" ID="ddlGender">
      <asp:ListItem Select="True" Value="M">Male</asp:ListItem>
      <asp:ListItem Value="F">Female</asp:ListItem>
      <asp:ListItem Value="U">Undecided</asp:ListItem>
    </asp:DropDownList>
    <br />
    <asp:Button runat="server" Text="Submit!"></asp:Button>
  </form>
</body>
</html>

当首次访问此页面时,将自动生成一个类,它包含编程创建控件体系结构的代码。这个控件体系结构如图3所示。

3 示例页面的控件体系结构

这个控件体系结构会被转化为类似下面的代码:

Page.Controls.Add( 
  new LiteralControl(@"<html>/r/n<body>/r/n
    <h1>Welcome to my Homepage!</h1>/r/n"));
HtmlForm Form1 = new HtmlForm();
Form1.ID = "Form1";
Form1.Method = "post";
Form1.Controls.Add(
  new LiteralControl("/r/nWhat is your name?/r/n"));
TextBox TextBox1 = new TextBox();
TextBox1.ID = "txtName";
Form1.Controls.Add(TextBox1);
Form1.Controls.Add(
  new LiteralControl("/r/n<br />What is your gender?/r/n"));
DropDownList DropDownList1 = new DropDownList();
DropDownList1.ID = "ddlGender";
ListItem ListItem1 = new ListItem();
ListItem1.Selected = true;
ListItem1.Value = "M";
ListItem1.Text = "Male";
DropDownList1.Items.Add(ListItem1);
ListItem ListItem2 = new ListItem();
ListItem2.Value = "F";
ListItem2.Text = "Female";
DropDownList1.Items.Add(ListItem2);
ListItem ListItem3 = new ListItem();
ListItem3.Value = "U";
ListItem3.Text = "Undecided";
DropDownList1.Items.Add(ListItem3);
Form1.Controls.Add(
  new LiteralControl("/r/n<br /> /r/n"));
Button Button1 = new Button();
Button1.Text = "Submit!";
Form1.Controls.Add(Button1);
Form1.Controls.Add(
  new LiteralControl("/r/n</body>/r/n</html>"));
Controls.Add(Form1);

注意 上面的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控件声明语法中的属性也已经被赋值。

我们将在这篇文章的后面更详细的探讨初始化阶段。视图状态非常重要的两个原因;一是服务器控件直到初始化阶段的末尾才会跟踪视图状态。二是当添加需要利用视图状态的动态控件时,这些控件需要在PageInit事件中被添加而不是在Load事件中,我们稍后就会看到。

阶段2-装载视图状态

仅当页面被回传时才会装载视图状态。在这个阶段,上次访问页面访问时被保存的视图状态数据被装载并且递归的传染到Page的控件体系结构。就是在这个阶段对视图状态进行校验。正如我们稍后所讨论的,视图状态可能由于各种原因而变得无效,例如视图状态tampering,在控件体系结构的中间插入动态控件。

未完待续

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值