HiddenField陷阱
1. 我放在HiddenField里的值呢?
通常作为客户端脚本与服务器端代码沟通桥梁之一的HiddenField控件,其实有一个小小的"陷阱"。如下面的代码片段:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
后台代码片段:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
HiddenField控件hdLastSelectedId位于被禁用的WebControl内部,因而呈现出来的HTML标记类似如下:
<input type="hidden" name="hdLastSelectedId" id="hdLastSelectedId" value="17" />
</div>
而浏览器在处理表单提交时,对于处于disabled的标记内或标示了disabled的所有input控件,将不会生成表单参数名称值对。也就是说,如果没有其他的状态恢复机制,标记为disabled的区域内的input值将会丢失。因此,上面的代码中的按钮点击事件将输出空字符串。而如果将上述HiddenField控件换成TextBox控件,则可以正常输出“17”。
ASP.net因为ViewState机制的存在,使得如TextBox等一些控件的值可以从ViewState中恢复,而HiddenField有些不一样,看下面的代码(Reflector HiddenField的代码)
{
base.OnPreRender(e);
if (!this.SaveValueViewState)
{
this.ViewState.SetItemDirty("Value", false);
}
}
而:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
也就是说默认情况下,仅在上面加粗的代码处的条件成立时,HiddenField的值才会被保存至ViewState,才有可能在回送时得到恢复。
因此,如果有像上面例子中HiddenField控件的应用场景(其实应该尽量避免),要想在回送后成功获取HiddenField的值,可以为HiddenField添加上ValueChanged事件。
2. Enabled,Disabled以及ReadOnly
WebControl.Enabled=false与HtmlControl.Disabled=true在很多时候容易混淆,其实两者有较大的区别。WebControl.Enabled=false一般将影响该Web控件的服务器端行为,以及客户端呈现,并且会将WebControl的所有子控件Enabled属性设为false。而HtmlControl.Disabled=true一般仅影响客户端呈现,且并不随控件层次传递。
MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.ui.webcontrols.webcontrol.enabled.aspx
http://msdn.microsoft.com/zh-cn/library/system.web.ui.htmlcontrols.htmlcontrol.disabled(VS.80).aspx
对于表单中的字段,上面两种情况在客户端最终产生的效果是一样的,即让浏览器在提交表单时忽略掉标记为disabled的表单字段。而即使是标记为disabled的字段,如果在客户端被修改为可用,且窜改了字段的值,则服务器端仍然会接受新提交的值,并不会做状态的校验,因此很容易被恶意用户伪造表单进行攻击。
如果是想让TextBox控件的值不能被修改,不是将其Enabled=false,而应该使用ReadOnly=true。这将使得TextBox在恢复状态时忽略掉客户端提交的表单中对应的字段值而只从ViewState中恢复。此外如果启用了ViewState加密,那么这样的表单字段才应该算是比较安全的。
HiddenField控件比较特殊,既没有Enabled属性,也没有ReadOnly属性,也无法使用内置的验证控件。原因可能很简单,因为它不需要UI呈现。但是因为这些原因,HiddenField是一个比较危险的控件,而在实际开发中往往有滥用的倾向,总以为Hidden了就谁也看不见。很多时候我们可以不用它而使用别的替代方式,比如直接使用ViewState(在性能允许的情况下最好启用ViewState加密)。或者至少确保提交的值在服务器端一定进行校验。具体依应用而定,这里就不讨论了。