ASP.NET 状态管理(视图状态 ViewState)
2015-09-27 23:44
639 查看
无论Web程序框架多么先进,它都不能改变一个事实:HTTP是一种无状态协议。
每次Web请求后,客户端和服务器端断开,同时ASP.NET引擎释放页面对象。这种架构保证了Web应用程序能够同时响应数千个并发请求而不会导致服务器内存崩溃。但其负面效应是你必须通过其他技术存储Web请求之间的信息并在需要的时候获取它们。
视图状态是在单个页面中保存信息的第一选择。ASP.NETWeb控件也使用试图状态在回发间保存属性值。通过页面内建的ViewState属性,你可以把自己的数据放入到视图状态集合中,可以保存的信息类型包括简单数据类型和自定义对象。
和ASP.NET中大多数的状态管理类似,视图状态依赖于字典集合。集合中每个项目通过一个唯一的字符串名字进行索引。
ViewState["Counter"]=1;
如果集合中没有叫做Counter的索引项,它将被自动添加。
如果已经存在,它将被替换。
ViewState通过键值来读取值,由于需要处理不同的数据类型,它将所有的数据保存为Object类型,因此在使用时涉及到数据类型的转换。
intcount;
if(VietState["Count"]!=null)
{
count=(int)ViewState["Count"];
}
如果试图查找一个集合中不存在的值,则会得到一个NullReferenceException异常,因此需要进行判空操作。
下面的代码演示了页面如何使用视图状态,它允许用户保存一系列的值,并将其恢复。这段代码使用递归遍历所有的子控件,由于控件ID在页面中是唯一的,所有它被用作视图状态的键值。
在视图状态中保存项目时,ASP.NET需要将它转换为比特流以便添加到页面的隐藏字段中,这个过程被叫做序列化。
对象在默认情况下不能被序列化,视图将一个不能序列化的对象保存到视图状态中,会得到一条错误信息,为使对象可序列化,需要在类的声明前加上Serializable特性。
因为Customer类现在被标记为可序列化的,所有它可以被保存在视图状态中:
也可以从中读取自定义对象:
为了让类可序列化,它需要符合下列条件:
类必须有Serializable特性。
它的任何基类都必须有Serializable特性。
所有成员变量必须为可序列化的数据类型。否则所有不可序列化的数据必须标识NonSerialized,它们将被简单的忽略。
示例:
效果:
视图状态是一个理想的状态管理方式,因为它既不消耗服务器内存也不加强额外限制(如超时)。那么什么原因会迫使你放弃视图状态而采用其他的状态管理方式呢?以下是3个可能的原因:
需要保存业务的核心数据,它们不允许被用户篡改。(聪明的用户可能会在回传请求中修改视图状态信息)
需要保存被多个页面使用的信息。(这种情况下考虑使用会话状态、cookie、查询字符串)
需要存储的信息量非常大,并且不希望因此影响页面传送时间。(这种情况下,考虑使用数据库或会话状态)
削减不必要的视图状态是减少页面传送时间的好办法,下面2种情况没有必要使用控件的视图状态:
控件从来不会变化(例如一个静态文字的按钮不需要使用视图状态)
控件在每次回传中被重新填充
将某个控件的EnableViewState属性设为false后,就可以关闭它的视图状态。而将页面的EnableViewState设为false后,可以关闭整个页面及其所有控件的视图状态(设置Page指令中的EnableViewState特性可以达到同样效果)。还可以在web.config文件里把<pages>元素的enableViewState特性设置为
false来禁用网站所有页面的视图状态。
可以关闭某个页面的视图状态,但通过对特定控件显式起用视图状态,从而达到选择性的覆盖页面设置!这项技术室ASP.NET4新增的,特别受热心于把页面视图状态减小到最少的开发人员的欢迎。为了达到这一目的,需要用到另一个叫做ViewStateMode的属性。
ViewStateMode可以应用到所有控件和页面,取值有以下3个:
Enable:只要EnableViewState属性启用了视图状态,视图状态就可以工作。
Disabled:该控件的视图状态不起作用,但该控件的子控件可以覆盖这个值。
Inherit:控件继承该控件的容器的ViewStateMode值。(默认选项)
为了有选择的使用视图状态,现在可以把页面的ViewStateMode设为Disabled来关闭页面级视图状态,需要使用视图状态的控件则单独设置该属性为Enable。请注意,我们并没有把EnableViewState设置为false,如果这么做的话,ASP.NET会完全关闭页面的视图状态,没有控件可以再起用它。
这个模型有点笨拙,但当视图状态的大小构成问题时它确实有用。唯一的缺点是你必须记得为那些具有需要持久化的动态值的控件或者必须依赖于视图状态才能正确工作的控件显式起用视图状态。
<inputtype="hidden"name="__VIEWSTATE"id="__VIEWSTATE"value="fakIvy3d8tjpX6spp/o260Nau17ykR"/>
视图状态信息以Base64编码的单个字符串形式保存,由于这些值并没有格式化为明文的形式,所有很多ASP.NET程序员误以为他们的视图状态数据时被加密的,但事实并非如此,恶意的用户可以在数秒内逆向的设计这个字符串从而查到你的视图状态数据。
有两个方法可以让视图状态更加安全:
使用散列码保证视图状态信息不被篡改(散列码是一种强校验码)。
启用视图状态加密
注1:
散列码默认就是启用的,你不必作任何多余的设置
注2:
启用加密可以在Page指令中或web.config文件中设置
<%@PageViewStateEncryptionMode="Always"/>
<pagesviewStateEncryptionMode="Always"/>
加密设定有3个选项:
Always:总是加密
Never:从不加密
Auto:总在控件要求时加密(默认选项)
当控件要求加密时,会调用Page.RegisterRequiresViewStateEncryption()方法来启用加密。但控件并没有绝对的控制力,如果页面加密模式是Never,那么控件即便调用了加密方法,也不会有任何作用。
非必要时不要加密视图状态数据。加密会导致性能下降,因为每次回发时Web服务器都需要执行加密和解密。
每次Web请求后,客户端和服务器端断开,同时ASP.NET引擎释放页面对象。这种架构保证了Web应用程序能够同时响应数千个并发请求而不会导致服务器内存崩溃。但其负面效应是你必须通过其他技术存储Web请求之间的信息并在需要的时候获取它们。
视图状态
视图状态是在单个页面中保存信息的第一选择。ASP.NETWeb控件也使用试图状态在回发间保存属性值。通过页面内建的ViewState属性,你可以把自己的数据放入到视图状态集合中,可以保存的信息类型包括简单数据类型和自定义对象。和ASP.NET中大多数的状态管理类似,视图状态依赖于字典集合。集合中每个项目通过一个唯一的字符串名字进行索引。
ViewState["Counter"]=1;
如果集合中没有叫做Counter的索引项,它将被自动添加。
如果已经存在,它将被替换。
ViewState通过键值来读取值,由于需要处理不同的数据类型,它将所有的数据保存为Object类型,因此在使用时涉及到数据类型的转换。
intcount;
if(VietState["Count"]!=null)
{
count=(int)ViewState["Count"];
}
如果试图查找一个集合中不存在的值,则会得到一个NullReferenceException异常,因此需要进行判空操作。
视图状态示例
下面的代码演示了页面如何使用视图状态,它允许用户保存一系列的值,并将其恢复。这段代码使用递归遍历所有的子控件,由于控件ID在页面中是唯一的,所有它被用作视图状态的键值。publicpartialclassChapter06_ViewStateTest:System.Web.UI.Page
{
protectedvoidbtnSave_Click(objectsender,EventArgse)
{
SaveAllText(this.Table1.Controls,true);
}
protectedvoidbtnRestore_Click(objectsender,EventArgse)
{
RestoreAllText(this.Table1.Controls,true);
}
privatevoidSaveAllText(ControlCollectioncontrols,boolsaveNested)
{
foreach(Controlcontrolincontrols)
{
if(controlisTextBox)
{
ViewState[control.ID]=((TextBox)control).Text;
}
//bool类型的saveNested参数给方法提供了更大的灵活性
//可以控制是否需要递归
if(control.Controls!=null&&saveNested)
{
SaveAllText(control.Controls,true);
}
}
}
privatevoidRestoreAllText(ControlCollectioncontrols,boolsaveNested)
{
foreach(Controlcontrolincontrols)
{
if(controlisTextBox)
{
if(ViewState[control.ID]!=null)
{
((TextBox)control).Text=ViewState[control.ID].ToString();
}
}
if(control.Controls!=null&&saveNested)
{
RestoreAllText(control.Controls,true);
}
}
}
}
在视图状态中保存对象
在视图状态中保存项目时,ASP.NET需要将它转换为比特流以便添加到页面的隐藏字段中,这个过程被叫做序列化。对象在默认情况下不能被序列化,视图将一个不能序列化的对象保存到视图状态中,会得到一条错误信息,为使对象可序列化,需要在类的声明前加上Serializable特性。
//指示一个类可以序列化
[Serializable]
publicclassCustomer
{
publicstringFirstName;
publicstringLastName;
publicCustomer(stringfirstName,stringlastName)
{
FirstName=firstName;
LastName=lastName;
}
}
因为Customer类现在被标记为可序列化的,所有它可以被保存在视图状态中:
Customercust=newCustomer("Malia","Carry");
ViewState["CurrentCustomer"]=cust;
也可以从中读取自定义对象:
Customercust;
if(ViewState["CurrentCustomer"]!=null)
{
cust=(Customer)ViewState["CurrentCustomer"];
}
为了让类可序列化,它需要符合下列条件:
类必须有Serializable特性。
它的任何基类都必须有Serializable特性。
所有成员变量必须为可序列化的数据类型。否则所有不可序列化的数据必须标识NonSerialized,它们将被简单的忽略。
示例:
publicpartialclassChapter06_ViewStateTest:System.Web.UI.Page
{
protectedvoidbtnSave_Click(objectsender,EventArgse)
{
Dictionary<string,string>dict=newDictionary<string,string>();
SaveAllText(this.Table1.Controls,dict,true);
ViewState["ControlText"]=dict;
}
protectedvoidbtnRestore_Click(objectsender,EventArgse)
{
if(ViewState["ControlText"]!=null)
{
Dictionary<string,string>dict
=ViewState["ControlText"]asDictionary<string,string>;
//KeyValuePair定义可设置或检索的键/值对。
foreach(KeyValuePair<string,string>itemindict)
{
Label1.Text+=item.Key+"="+item.Value+"<br/>";
}
}
}
privatevoidSaveAllText(ControlCollectioncontrols,Dictionary<string,string>dict,boolsaveNested)
{
foreach(Controlcontrolincontrols)
{
if(controlisTextBox)
{
dict.Add(control.ID,((TextBox)control).Text);
}
if(control.Controls!=null&&saveNested)
{
SaveAllText(control.Controls,dict,true);
}
}
}
}
效果:
视图状态评估
视图状态是一个理想的状态管理方式,因为它既不消耗服务器内存也不加强额外限制(如超时)。那么什么原因会迫使你放弃视图状态而采用其他的状态管理方式呢?以下是3个可能的原因:需要保存业务的核心数据,它们不允许被用户篡改。(聪明的用户可能会在回传请求中修改视图状态信息)
需要保存被多个页面使用的信息。(这种情况下考虑使用会话状态、cookie、查询字符串)
需要存储的信息量非常大,并且不希望因此影响页面传送时间。(这种情况下,考虑使用数据库或会话状态)
有选择的禁用视图状态
削减不必要的视图状态是减少页面传送时间的好办法,下面2种情况没有必要使用控件的视图状态:控件从来不会变化(例如一个静态文字的按钮不需要使用视图状态)
控件在每次回传中被重新填充
将某个控件的EnableViewState属性设为false后,就可以关闭它的视图状态。而将页面的EnableViewState设为false后,可以关闭整个页面及其所有控件的视图状态(设置Page指令中的EnableViewState特性可以达到同样效果)。还可以在web.config文件里把<pages>元素的enableViewState特性设置为
false来禁用网站所有页面的视图状态。
可以关闭某个页面的视图状态,但通过对特定控件显式起用视图状态,从而达到选择性的覆盖页面设置!这项技术室ASP.NET4新增的,特别受热心于把页面视图状态减小到最少的开发人员的欢迎。为了达到这一目的,需要用到另一个叫做ViewStateMode的属性。
ViewStateMode可以应用到所有控件和页面,取值有以下3个:
Enable:只要EnableViewState属性启用了视图状态,视图状态就可以工作。
Disabled:该控件的视图状态不起作用,但该控件的子控件可以覆盖这个值。
Inherit:控件继承该控件的容器的ViewStateMode值。(默认选项)
为了有选择的使用视图状态,现在可以把页面的ViewStateMode设为Disabled来关闭页面级视图状态,需要使用视图状态的控件则单独设置该属性为Enable。请注意,我们并没有把EnableViewState设置为false,如果这么做的话,ASP.NET会完全关闭页面的视图状态,没有控件可以再起用它。
这个模型有点笨拙,但当视图状态的大小构成问题时它确实有用。唯一的缺点是你必须记得为那些具有需要持久化的动态值的控件或者必须依赖于视图状态才能正确工作的控件显式起用视图状态。
视图状态安全
<inputtype="hidden"name="__VIEWSTATE"id="__VIEWSTATE"value="fakIvy3d8tjpX6spp/o260Nau17ykR"/>视图状态信息以Base64编码的单个字符串形式保存,由于这些值并没有格式化为明文的形式,所有很多ASP.NET程序员误以为他们的视图状态数据时被加密的,但事实并非如此,恶意的用户可以在数秒内逆向的设计这个字符串从而查到你的视图状态数据。
有两个方法可以让视图状态更加安全:
使用散列码保证视图状态信息不被篡改(散列码是一种强校验码)。
启用视图状态加密
注1:
散列码默认就是启用的,你不必作任何多余的设置
注2:
启用加密可以在Page指令中或web.config文件中设置
<%@PageViewStateEncryptionMode="Always"/>
<pagesviewStateEncryptionMode="Always"/>
加密设定有3个选项:
Always:总是加密
Never:从不加密
Auto:总在控件要求时加密(默认选项)
当控件要求加密时,会调用Page.RegisterRequiresViewStateEncryption()方法来启用加密。但控件并没有绝对的控制力,如果页面加密模式是Never,那么控件即便调用了加密方法,也不会有任何作用。
非必要时不要加密视图状态数据。加密会导致性能下降,因为每次回发时Web服务器都需要执行加密和解密。
相关文章推荐
- Asp.net中static变量和viewstate的使用方法(谨慎)
- ASP.NET MVC验证框架中关于属性标记的通用扩展方法
- ASP.NET WebAPI 05 参数绑定
- ASP.NET Identity
- ASP.NET餐饮管理系统制作代码分享
- ASP.NET Web API 异常日志记录
- ASP.NET MVC 2右键菜单和简单分页实例讲解
- asp.net分页功能实现
- ASP.NET 5介绍
- 调试ASP.NET2005/2008时,端口不正确的解决三套方案
- ASP.NET无刷新分页简单实现
- ASP基础知识Command对象讲解
- asp知识整理笔记3(问答模式)
- ASP.NET无刷新分页简单实现
- 调试ASP.NET2005/2008时,端口不正确的解决三套方案
- asp.net分页功能实现
- ASP.NET MVC 2右键菜单和简单分页实例讲解
- ASP基础知识Command对象讲解
- asp知识整理笔记3(问答模式)
- C#分布式缓存二:Asp.Net中使用Couchbase