ASP.NET 回发详解

相信很多开发过AJAX的朋友都遇到过回发和回调的问题,今天我们就撇开AJAX来单独谈一谈回发,并通过一组简单的示例进行释疑。我们先在页面上添加一个客户端链接控件,设置其Id为“aLink”,看起来应该像这样:

1:<a id="aLink" onclick="__doPostBack('aLink','[aLink_EventArg]')>aLink</a>

保存并在浏览器中查看,点击链接后系统会提示脚本错误,原因很简单,查看页面源代码就知道,当前不存在__doPostBack这个回发函数,这就与调用了一个不存在的Javascript函数一样。

先把这个问题放在一边,接下来我们在页面上添加一个服务器端按钮控件,设置其Id为“btn1”,并将其onClientClick属性设置为一个回发函数,看起来应该像这样:

1:<asp:Button ID="btn1" runat="server" Text="Btn1" OnClientClick="__doPostBack('btn1','[btn1_EventArg]')" />

保存并在浏览器中查看,点击以后出现和刚才一样的脚本错误,原因之前已经说了,同时说明.NET Framework不会为服务器端控件自动生成回发函数。

我们把这个问题也放在一边,接下来再在页面上添加一个服务器端按钮控件,这次在前端不需要设置额外的属性,所以它看起来应该像这样:

1:<asp:Button ID="btn2" runat="server" Text="Btn2" />

这还没完,我们需要切换到代码视图,并重写Page的呈现方法,看起来应该像这样:

1:protected override void Render(HtmlTextWriter writer) { 
2: this.btn2.OnClientClick += ClientScript.GetPostBackEventReference(this.btn2, "[btn2_EventArg]", true); 
3: base.Render(writer); 
4:}

GetPostBackEventReference方法的作用是返回一段用于客户端事件的字符串,以触发到服务器端的回发。接收的第一个参数是用来处理回发的控件,第二个是用来处理额外事件信息的字符串形式参数,第三个是是否注册事件引用以进行验证。跟踪这个方法所返回的字符串就会发现,它与我们为Btn1所写的回发字符串别无二致。保存这些修改并在浏览器中查看,我们惊喜地发现Btn2可以正常工作(尽管光从页面源代码比较Btn1和Btn2无法看出有什么区别),更加令人惊喜的是,假如你在IE下进行调试(笔者的IE版本为IE8),那么会发现连之前不能工作的两个控件也运行地很好。其实原因是因为GetPostBackEventReference不仅仅返回一段用来触发回发的字符串,而且在服务器端注册了回发事件,在页面的源代码中我们可以看到系统自动生成了__doPostBack函数。但如果你还装有其它的浏览器(Chrome或是Firefox),那么用它们来打开页面,你就会发现点击Btn1将会使.NET Framework抛出一个异常,具体内容如下:

 

 

 

.NET Framework出于安全考虑需要为服务器端控件的回发和回调事件进行注册,因为Btn1没有进行过类似注册(Btn2使用GetPostBackEventReference进行了注册),所以会抛出异常,这也正是aLink不会引起异常的原因(因为它是客户端控件)。你可以手动关闭对回发和回调的验证,方法是将Page或是Web.config中的EnableEventValidation属性设置为False(如果两者设置有冲突,以Page的为准),看起来应该像这样:

1:<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ClientPostback.aspx.cs" Inherits="WebApplication1.ClientPostback"  EnableEventValidation="false" %>

或是:

1:<system.web> 
2: <pages enableEventValidation ="false"></pages> 
3:</system.web>

但是这种无视安全性的做法是不值得推荐的,除非回发或回调的事件是不可预测的,否则应该为每一个回发或回调事件进行注册。要想为Btn1进行注册,需要回到代码视图,在之前的页面呈现方法中添加注册(注册这一行为只能写在Page.Render中,同时需要注意注册的控件唯一标识和参数必须与前端保持一致),修改后的Render看起来应该像这样:

1:protected override void Render(HtmlTextWriter writer) { 
2: Page.ClientScript.RegisterForEventValidation(this.btn1.UniqueID,"[btn1_EventArg]"); 
3:    this.btn2.OnClientClick += ClientScript.GetPostBackEventReference(this.btn2, "[btn2_EventArg]", true); 
4:    base.Render(writer); 
5:}

现在即使我们在非IE浏览器下触发回发事件也能够正常运行了。目前Btn1和Btn2所包含的代码可以说是等价的,但要想进行回发还有更加简便的方法。

再在页面中添加一个服务器端按钮控件,将其Id设置为“btn3”,并将它的UseSubmitBehavior属性设置为False,看起来应该像这样:

1:<asp:Button ID="btn3" runat="server" Text="Btn3" UseSubmitBehavior="False" onclick="btn3_Click" />

UseSubmitBehavior的默认属性是True,这意味着点击按钮默认将会触发浏览器的提交操作,而设置成False意味着点击按钮将会触发.NET Framework的回发操作,请注意触发源和触发行为的不同。设置了UseSubmitBehavior属性以后系统将会自动为其进行注册,注册使用的控件唯一标识是控件的UniqueID,参数为空字符串。

接下来我们再在页面中添加一个服务器端按钮,将其Id设置为“btn4”(好吧,我承认用数字进行排序的Id过不了多久就会让人产生迷茫,不过作为一个小例子,我想把更多的精力放在叙述的流畅度上而不是绞尽脑汁为它们起一个优雅的名字),并将其onClientClick设置为“__doPostBack('btn3','')”,看起来应该像这样:

1:<asp:Button ID="btn4" runat="server" Text="Btn4" OnClientClick="__doPostBack('btn3','')" />

保存并在浏览器中查看,点击Btn4会发现,虽然我们没有进行注册,但是它运行地很好,这说明回发事件的注册与服务器控件本身的ID无关,只要保证回发事件中的UniqueID被注册过(Btn3被系统自动注册,前面已经说到过),就能成功进行调用。

如果你在btn3_Click中对sender进行捕捉并且足够细心,你就会发现回发和提交的最大不同:如果通过提交进入,那么sender将是触发提交的那个按钮;如果通过回发进入,那么sender将是ID与回发函数中的UniqueID对应的那个按钮。也就是说,在Click方法中,后端无法知道到底是谁真正触发了它,因为你跨过了浏览器,直接向服务器端发送了请求。

转载请保留作者姓名及原网址,点此打开原文。

 

转自:http://www.cnblogs.com/jiaowei/archive/2010/08/16/1800989.html
posted @ 2010-08-16 23:40  唔愛吃蘋果  阅读(458)  评论(0编辑  收藏  举报