前言
最近在招聘面试的过程中,我经常会问应聘者一些基础的问题,例如:“谈谈你对viewstate的理解”。发现很少有人能回答出来。
可能很多人会笑话,这真是个老掉牙的而且没有实际意义的问题,但我就发现很少有人能给出很满意的答复。对于不同的回答,其实是可以推断出回答者的性格和态度的。有的求职者直接这样反驳的回复:“viewstate那是以前asp.net的东西了,现在早就流行用mvc了,谁还用那东西......”,“会用三层开发,能把功能实现就行了,探究这个意义不大吧......”,“这东西听说过,但是具体不了解,听说很消耗性能的,听人家说做大项目大网站的不建议使用”。反正就是各种奇葩的回复吧。说明很多人对待技术其实是“不求本质”的。难道基础真的不重要吗?
其实有个别的人,已经回答的“沾边”了,但是却存在种种误解。这不禁让我觉得,有太多人写书、教学都是在“误人子弟”。
正文
1.有种普遍的误解是这样的:viewstate保存了控件的值,放在隐藏域里面一起提交给服务器端了,然后服务器端回发之后,页面上还能显示之前输入的值。放在真实场景中,在一个最简单的aspx页面中,有N个表单项(最典型的是服务器控件的文本框),我们输入了信息后,点击提交,此时会发送请求给服务器端,回发完成页面刷新之后,文本框中还能看到之前我们输入的值。可能有很多书籍,或者教学的老师,也都是这样传授的吧。或许是因为有些知识是翻译过来的有点含糊,所以产生了误解。
拆穿这个荒谬的“谎言”其实很简单,把这个aspx页面中指定文本框的viewstate禁用掉(默认是将该服务端控件的EnableViewState 属性设为 false),然后再重复刚才的操作......其实不难发现,页面上的文本框里依然能够保存我们之前输入的值。由此可以断定,“回发后恢复控件的值”与viewstate是没有半毛钱关系的。不信的可以自己动手试试。
那可能有人会疑惑了,那还要viewstate有个啥用啊?每次生成一坨坨的,http提交也是浪费啊!其实页面上生成的_viewstate隐藏域上,value中确实包含有控件相关的信息,也确实会随着表单http post提交给服务器端去。主要是有啥用呢?比如有些服务器端控件比较特殊,例如Lable(它在客户端最终生成html后好像就是个span标签),有时候我们想在服务器端获取到它的值或者属性,例如比较常见的Text文本值。span这种标签,其实它是不属于“表单项”的,换句话来说,就是它不像文本框,选择框...那些标签,它的属性和值默认是不能随着http post(form表单)提交给服务器的。其实这个时候,就需要viewstate隐藏域来帮忙了。如果不相信,可以禁用Lable控件的viewstate或者直接禁用该aspx页面的viewstate,看在服务端代码里能否获取到Lable的Text。
2.禁用了viewstate,访问aspx页面,html就不会有__VIEWSTATE了,服务器端页面类中也不会用到任何的viewstate了。
页面本身将 20 字节左右的信息保存在 ViewState 中,用于在回传时将 PostBack 数据和 ViewState 值分发给正确的控件。因此,即使该页面或应用程序禁用了 ViewState,仍可以在 ViewState 中看到少量的剩余字节。
3.viewstate是加密的
严格来讲,我们看到的生成的html页面viewstate值的“乱码”,其实只是简单的base64编码,可以很轻易还原出来的。它是以类似xml树的结构保存的,对应的是页面类中的一个叫viewstate的属性,通过string索引器访问,通俗点就是通过“键值对”的方式存储和访问。当然,它也不是一点也不安全的,默认是有通过SHA-1算法来进行验证的,验证的validationKey默认是自动生成的。
所以,在多台服务器部署的情况下,需要配置想通的validationKey,否则在Server A生成的viewstate可能在Server B中就是无效的,因为mac不同导致自动生成的validationKey不一致。解决办法很简单,只需要在web.config中,在配置<machineKey>节点下配置即可。
本文目的只是在于纠正大家对viewstate的一些常见的误解,篇幅有限,并未深入去探讨其内部如何存储的、在页面生命周期中如何被处理、在哪个事件方法中被加载......有兴趣的朋友,可以自己去研究。细细品味,其实webform也不是像传说的那么不给力那么臃肿,还是在于使用者。其实它里面有很多设计思想都是很优秀的,哪怕是应用的不广泛了,也是有学习和研究的价值的。