在Asp.net 中,你可知道在客户端是如何触发服务端事件的吗?要分析这种情况,须从两种情况入手,具体来看!
一》WebControls中的Button 和HtmlControls中的Type为submit的HtmlInputButton
这两种按钮最终到客户端的表现形式为: < input name="Submit1" id="Submit1" type="submit" value=”Submit”>,这是Form表单的提交按钮,点击以后会作为参数发送到服务端,参数是这样的: 控件的name属性=控件的value值,对应上面的例子就是:Submit1= Submit。 服务端会根据接收到的控件的name属性的这个key来得知是这个按钮被点击了,从而在服务端触发这个按钮的点击事件。
二》HtmlControls 中的 Type为button的HtmlInputButton 和其它所有的控件事件,比如LinkButton点击,TextBox的Change事件等等:
这些事件在客户端产生后会经过一个统一的机制发送到服务端。
1. 首先asp.net页框架会使用两个Hidden域来存放表示是哪个控件触发的事件,以及事件的参数:
< !—表示触发事件的控件,一般是这个控件的name -->
< input type="hidden" name="__EVENTTARGET" value="" />
< !—表示触发事件的参数,一般是当某个控件有两个以上的事件时,用来区别是哪个事件 -->
< input type="hidden" name="__EVENTARGUMENT" value="" />
2. 服务端会生成一个javascript的方法来处理所有这些事件的发送,这段代码是:
< script language="javascript">
< !--
function __doPostBack(eventTarget, eventArgument) {
var theform = document.WebForm2;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// -->
< /script>
3. 每个会引发服务端事件的控件都会在响应的客户端事件中调用上面的代码:
比如,HtmlControls 中的 Type为button的HtmlInputButton的点击事件
< !—客户端的点击事件调用__doPostBack,eventTarget 参数为'Button2',表示是name为'Button2’控件触发的事件,eventArgument 为空,表示这个Type为button的HtmlInputButton只有一个客户端触发的服务端事件-->
< input language="javascript" οnclick="__doPostBack('Button2','')" name="Button2" id="Button2" type="button" value="Button" />
又比如,TextBox控件的Change事件
< !—客户端的onchange事件调用__doPostBack,eventTarget 参数为’TextBox1’,表示是name为’TextBox1’控件触发的事件,而TextBox控件只有一个客户端触发的服务端事件TextChanged,故服务器就会去触发这个TextBox的TextChanged事件->
< input name="TextBox1" type="text" id="TextBox1" οnchange="__doPostBack('TextBox1','')" language="javascript" />
4. 客户端触发事件后调用__doPostBack方法,将表示触发的控件源的eventTarget 和事件参数eventArgument分别付给两个隐藏域__EVENTTARGET和__EVENTARGUMENT,然后提交Form,在服务端根据__EVENTTARGET和__EVENTARGUMENT来判断是哪个控件的什么事件触发了
----------------------------------------------------------------------
第二章 、 PostBack 的原理
__doPostBack 是一个纯粹并且是非常简单的 javascript 函数,大部分的页面 PostBack 都是由它触发的。注意,这里是 “ 大部分 ” ,因为只有两个 Web Server Control 会自己触发页面的 PostBack, 其它的所有控件都是通过 __doPostBack 函数触发页面的 PostBack ,那先来看一下这个函数的定义吧:
CODE1:
< input type="hidden" value="" />
< input type="hidden" value="" />
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
通过上面的代码可以看到, __doPostBack 带有两个参数, eventTarget 是标识将要引发页面 PostBack 的控件 ID , eventArgument 参数提供了在引发页面 PostBack 事件时所带的额外参数。当然这个函数被函数时,这两个参数的值将赋值给页面的两个隐含变量 __EVENTTARGET 和 __EVENTARGUMENT ,然后调用页面的 submit 方法提交页面表单。这就是为什么我们可以通过 Request.Form[“__EVENTTARGET”] 获取得到引发页面 PostBack 的控件 ID 的原因。
了解了 __doPostBack 函数后,我们可以很容易的利用它非常方便地自己触发自定义的 PostBack 事件。那上面也说了,大部分的控件都是调用
第三章 Button PostBack 做法
引了页面的 PostBack ,只有两个控件是例外, Button 和 ImageButton ,正是因为它们不是通过调用 __doPostBack 来回发事件,所以通过表单隐含变量 __EVENTTARGET 和 __EVENTARGUMENT 是无法获取得到引发 PostBack 的 Button 或 ImageButton 的 ID 和参数值的,可通过下面的方式实现
1 )在页面中加如 LinkButton ,页面就会在页面中加载 POSTBACK 所需的 JS
< input type="hidden" value="" />
< input type="hidden" value="" />
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
2 )利用 GetPostBackEventReference 给客户端生成 __doPostBack()
如:
比如前台页面
< asp:Button id ="Button1" runat ="server" Text ="Button">< / asp:Button >
( 1 )
< a href ="#" onclick ="document.getElementById('Button1').click()"> 触发服务器端按钮事件 < / a >
( 2 )
利用 GetPostBackEventReference 给客户端生成 __doPostBack()
前台
< a href ="#" onclick ="< %=PostBack()%>"> 触发服务器端按钮事件 < / a >
后台
protected string PostBack()
{
return this .Page.GetPostBackEventReference( this .Button1,"haha");
}
通过 __EVENTARGUMENT="haha" 可以判断是不是点了那个链接的 PostBack 把 Button1 的按钮事件这么写:
if (Request["__EVENTARGUMENT" ]=="haha")
{
Response.Write(" 这个是链接的 PostBack");
}
else
{
Response.Write(" 这个不是链接的 PostBack");
}
Bug :
问题:『使用 __doPostBack 会导致』
回发或回调参数无效。在配置中使用 < pages enableEventValidation="true"/> 或在页面中使用 < %@ Page EnableEventValidation="true" %> 启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用 ClientScriptManager.RegisterForEventValidation 方法来注册回发或回调数据以进行验证。
问题分析及解决方案:『来源网络』
这个要具体分析。本来这个措施是 asp.net2.0 用来防止客户端 “ 欺诈 ” 服务器端的。例如本来输出到客户端的一个事件被触发时需要回发的命令是 “__doPostback('ctl01$abc','user_1')” 的,如果采取采取手段把回发参数由 user_1 改为 user_5 了,服务器端会重新核对输出的是不是 user_5 ,发现和这个页面上一个输出的脚本不一致,就会产生这个异常。
但是,很多程序员写的程序按照过去的习惯(或者按照更加高级灵活的设计例如一些 Ajax 组件)没有考虑这个问题或者是忽略这个欺诈的可能性,写的程序可能会修改参数或者修改目标控件。
因此这样具体问题具体分析。不太可能跟浏览器距离服务器的远近有关,应该还是编程逻辑问题。你应该对出异常的画面以及所使用的数据进行分析。有时候,经常也需要将这个参数设置为 false ,放弃安全管理