ViewState概述
页面在初始化的时候,asp.net会在页面内建ViewState属性,我们可以将需要保存的数据放到视图状态的集合中,以达到在页面回发的时候保存数据的目的。
使用ViewState以前,需要注意以下内容:
1.ViewState依赖于字典集合。
2.ViewState中的每一项通过唯一的字符串名字进行索引。
我们在给视图集合的某个索引项赋值的时候,如果视图集合中存在该索引项,则赋值;如果没有,则改索引项将会被自动添加并赋值。
在尝试从视图集合中取出某个索引项的值的时候,如果视图集合中不存在此索引项的时候,将会抛出异常。
因此我们在取值的时候,通常会加个判断。
例如:
{
int test = ( int )ViewState[ " test " ];
}
3.ViewState可以保存简单数据类型和自定义对象。
4.任何通过索引字符串从ViewState中取出来的数据都是Object类型,我们需要显式的将其转换成需要的类型,如上例。
使用ViewState的一个例子
< div >
< asp:TextBox ID ="TextBox1" runat ="server" ></ asp:TextBox >< br />
< asp:TextBox ID ="TextBox2" runat ="server" ></ asp:TextBox >< br />
< asp:TextBox ID ="TextBox3" runat ="server" ></ asp:TextBox >< br />
< asp:TextBox ID ="TextBox4" runat ="server" ></ asp:TextBox >< br />
< asp:Button ID ="Button1" runat ="server" Text ="Save" onclick ="Button1_Click" />
< asp:Button ID ="Button2" runat ="server" Text ="Restore" onclick ="Button2_Click" />
< asp:Button ID ="Button3" runat ="server" Text ="SaveWithDictionary" onclick ="Button3_Click" />
< asp:Button ID ="Button4" runat ="server" Text ="Display" onclick ="Button4_Click" />< br />
< asp:Label ID ="Label1" runat ="server" Text ="" ></ asp:Label >
</ div >
</ form >
将页面上所有的TextBox的值存入视图状态。
{
SaveAllText(this.Controls);
}
private void SaveAllText(ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is TextBox)
{
ViewState[control.ID] = ((TextBox)control).Text;
}
if (control.Controls != null)
{
SaveAllText(control.Controls);
}
}
}
从ViewState中取出各TextBox的值,并还原于页面。
{
LoadAllText(this.Controls);
}
private void LoadAllText(ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is TextBox && ViewState[control.ID] != null)
{
((TextBox)control).Text = (string)ViewState[control.ID];
}
if (control.Controls != null)
{
LoadAllText(control.Controls);
}
}
}
ViewState的实现过程:
ViewState在保存数据的时候,asp.net会将要保存的数据转换成比特流,以便能够保存在页面隐藏的input当中。
这个将数据转换成比特流的过程,也叫序列化。
在页面回发的时候,这些被序列化后的数据和正常数据一样被提交到服务器端。
在服务器端将这些数据反序列化以后,还原成ViewState的键值对形式,我们便可以通过ViewState的字符串索引来访问这些数据。
ViewState能够保存的数据类型:
从ViewState的实现过程中可以看出,使用ViewState保存数据的时候,被保存的数据需要进行序列化和反序列化的操作。
因此,某种数据类型是否能够保存在视图状态中,取决于这种数据类型能否被序列化和反序列化。
我们可以同在类声明前加上[Serializable]标记符,声明自定义对象是允许被序列化的。
例如:
public class Test
{ }
这样我们就声明了一个允许被序列化和反序列化的类。
因此我们msdn中看到一个类如果有Serializable特性,则表明这个类实例化后的对象便可以放入ViewState当中去。
下面这个例子是将一个Dictionary对象放入ViewState中的测试。Dictionary具有Serializable的特性,允许被序列化。
仍然使用上面例子中的html,在后台页面有如下代码。
将页面上所有TextBox的值存入ViewState中的一个Dictionary对象当中去。
{
Dictionary<string, string> textToSave = new Dictionary<string, string>();
SaveAllTextWithDictionary(textToSave, this.Controls);
ViewState["ControlsText"] = textToSave;
}
private void SaveAllTextWithDictionary(Dictionary < string , string > textToSave, ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is TextBox)
{
textToSave.Add(control.ID, ((TextBox)control).Text);
}
if (control.Controls != null)
{
SaveAllTextWithDictionary(textToSave, control.Controls);
}
}
}
遍历ViewState中索引项为"ControlsText"的项,其内容为一个Dictionary对象。
{
DisplayAllText();
}
private void DisplayAllText()
{
if (ViewState["ControlsText"] != null)
{
Dictionary<string, string> savedText = (Dictionary<string, string>)ViewState["ControlsText"];
foreach (KeyValuePair<string, string> item in savedText)
{
this.Label1.Text += (string)item.Key + ":" + (string)item.Value + "<br/>";
}
}
}
ViewState的性能和安全
从ViewState的实现过程可以看出,试图状态通过Post的方式将数据内容存放到一个Base64位编码的单一字符串回传到服务器端,然后在反序列化回传的字符串并还原控件的状态。
因此使用ViewState势必会增大客户端和服务器端的数据传输量,在web应用当中,过大的数据传输两会影响系统性能和用户体验。
以下几种情况,应当尽量避免使用ViewState:
1.需要传送大量的数据时。
可以考虑采用数据库或者会话的形式进行数据的交互和保存。
2.传送的数据有较高的安全需求时。
ViewState虽然表面看起来是无顺序的一堆字符,但其实仍然是以明文的形式存放的,并没有进行加密处理。在客户端仍然可以获取或者篡改其值来欺骗服务器端。
3.控件的值是静态的时候。
4.控件的值需要在回传时重新加载数据。