Asp.Net 中ViewState—视图状态浅析
Asp.Net 中引入ViewState的背景:
由于Http请求是一种无状态请求,即Web服务器不会记录任何客户端的独特信息,以最大效率的运行。然而此时(假设是用纯Asp 语言),假若我们提交了文本框至服务器,在提交过程中,从服务器端重新返回实例化一个页面类的对象,而这个对象页并没有保留住我们之前输入文本框的值,即我们的值丢失了!
正是在上述背景下,作为Asp 与 .NET框架的完美结合体——Asp.Net 产生了。为了克服这种障碍,其引入的状态管理功能,即应用ViewState可以在同一页面的多次服务器请求之间保留页以及控件的值,成功克服了这种困难!
在默认情况,Asp.Net页框架使用ViewState在多次回送之间保留页和控件值,而在发送至客户端浏览器的HTML代码上,则具体表现为一个或多个隐藏的<input type="Hidden">字段。
下面即就ViewState 所针对的两种保存值对象——页值和控件值,分而讨论之:
ViewState 保留页值的方法:
先看初始状态下,所建立服务器端HTML代码:
<div>
<asp:Label ID="lbelDemo" runat="server" Text="lbelInit"></asp:Label>
<br />
<asp:Button ID="btnSub1" runat="server" Text="btnSub1"
onclick="btnSub1_Click" />
<asp:Button ID="btnSub2" runat="server" Text="btnSub2" />
</div>
</form>
其对应的后台代码为:
2 {
3 protected void Page_Load(object sender, EventArgs e)
4 {
5 if (!IsPostBack)
6 {
7 //赋予ViewState为整数int型,初值为1
8 ViewState["count"] = 1;
9 }
10 if (IsPostBack)
11 {
12 //在回送状态下,实现ViewState的逐个累加
13 ViewState["count"] = (int)ViewState["count"] + 1;
14 }
15
16 }
17 protected void btnSub1_Click(object sender, EventArgs e)
18 {
19 //旨在通过点击btnSub1触发事件,实现将ViewState状态值,及时反馈在lbelDemo中
20 lbelDemo.Text = ViewState["count"].ToString();
21 }
22 }
在浏览器上,初次展现为(如下图):
查看其源代码为:
<form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTExNjMzNDIxNjQPFgIeBWNvdW50AgFkZD/xqNtuWCI2N3knwGlV+hqR7lUO" />
</div>
<div>
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAwKRvOPFDgKU2NnBCwKvwffWBd/L4HJDqcil+WEelebQudVq4Brk" />
</div>
<div>
<span id="lbelDemo">lbelInit</span>
<br />
<input type="submit" name="btnSub1" value="btnSub1" id="btnSub1" />
<input type="submit" name="btnSub2" value="btnSub2" id="btnSub2" />
</div>
</form>
</body>
此时可见,在源代码中已经维持了一个隐藏的、用于保存值的字段,代码为:
通过这个隐藏字段(其实质为本部分讨论的页值保存,以及马上讲的控件值保存项),即可以实现页值,在这里即ViewState["count"]保存,在这里可以通过btnSub1的触发事件实现,见下图,可见lbelDemo的值随点击次数逐次累加:
这样通过在页面级别的ViewState["count"],这样的键/值,实现了在页面的往复间依然保留页值的功能。
ViewState 保留控件值的方法:
在这里采用Label这样一个比较特殊的服务器端控件(因为在HTML 中并不具备Label控件,这就依赖于.NET 的CLR实现将Label 转化为Span ,从而实现解析的目的)。
依然采用上述的例子,做一些改动:
初始状态下的,服务器端代码不变,为:
<div>
<asp:Label ID="lbelDemo" runat="server" Text="lbelInit"></asp:Label>
<br />
<asp:Button ID="btnSub1" runat="server" Text="btnSub1"
onclick="btnSub1_Click" />
<asp:Button ID="btnSub2" runat="server" Text="btnSub2"
onclick="btnSub2_Click"/>
而其对应后台代码,做了较大改动,代码为:
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSub1_Click(object sender, EventArgs e)
{
lbelDemo.Text = "Label Text has been Changed";
}
protected void btnSub2_Click(object sender, EventArgs e)
{
}
}
这样在初始页面、点击btnSub1、点击btnSub2之后页面的状态图示,如下:
可以看到初始状态同页值初始状态,而点击btnSub1和btnSub2之后,页面显示相同,这就是因为:点击btnSub1之后,后台CLR运营的ViewState更新了lbelDemo属性的变化,并及时更新,同时反馈、显示在客户端HTML中。当btnSub2点击后,由上一篇文章《Asp.Net 生命周期浅析》中已经介绍页面的加载顺序了,在此不再鳌述,ViewState值加载进lbelDemo,从而实现控件值保留。
这样就实现了ViewState保留控件值的目的。
附:
1.对于利用ViewState保留控件值的方法,要依赖于所有控件都具有的属性——EnableViewState的True 或 False。ex,在Label控件中将其属性ViewState设置为false后,展示的三个页面为:
可见点击btnSub2之后,展示的是初始lbelDemo的Text值,这是因为"禁用"控件ViewState属性所致;
2. 对于利用ViewState保留控件值的方法。当对于TextBox等控件时,即使EnableViewState设置为false,照样可以实现保留功能,原因就在于其本身携带其属性值,这在初始化页面时已经加载了!所以ViewState并不是对所有服务器端控件都是必须的;
3.对于隐藏的ViewState字段,如果携带大量数据,将降低数据传输效率(而且好像有最大量限制。),可以考虑禁用一些控件的ViewState属性,然这不是本文着重,不鳌述。
综论之,Asp.Net 所采用的视图状态管理,极大地改进了性能。本文仅就其两类使用方法稍加概述,呵呵