第一章、 Asp.net中服务端控件事件是如何触发的
Asp.net
中在客户端触发服务器端事件分为两种情况:
一.
WebControls
中的
Button
和
HtmlControls
中的
Type
为
submit
的
HtmlInputButton
这两种按钮最终到客户端的表现形式为:
<
input
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" value="" />
<!―
表示触发事件的参数
,
一般是当某个控件有两个以上的事件时,用来区别是哪个事件
-->
<
input
type="hidden" value="" />
2.
服务端会生成一个
jscript
的方法来处理所有这些事件的发送,这段代码是:
<
script
language="javascript" type="text/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" Button2','')" type="button"
value="Button" />
又比如,
TextBox
控件的
Change
事件
<!―
客户端的
onchange
事件调用
__doPostBack
,
eventTarget
参数为
’TextBox1’
,表示是
name
为
’TextBox1’
控件触发的事件,而
TextBox
控件只有一个客户端触发的服务端事件
TextChanged
,故服务器就会去触发这个
TextBox
的
TextChanged
事件
->
<input type="text" 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()
前台
利用 GetPostBackEventReference 给客户端生成 __doPostBack()
前台
<
a
href
="#"
onclick
="<%=PostBack()%>">
触发服务器端按钮事件
</
a
>
后台
protected
string PostBack()
{
return this.Page.GetPostBackEventReference(this.Button1,"haha");
}
{
return this.Page.GetPostBackEventReference(this.Button1,"haha");
}
通过
__EVENTARGUMENT="haha"
可以判断是不是点了那个链接的
PostBack
把
Button1
的按钮事件这么写:
if
(Request["__EVENTARGUMENT" ]=="haha")
{
Response.Write(" 这个是链接的 PostBack");
}
else
{
Response.Write(" 这个不是链接的 PostBack");
}
{
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
,放弃安全管理
来自:sightboy的专栏