ASP.NET 2.0中加入的Cross-Page Postback机制让我们ASP.NET开发人员有了轻松的(无需自定义)跨页面发POST请求的方式。但在实际开发时,难免遇到点小问题。比如在点击按钮发生跨页提交的时候,想先弹出一个JavaScript的confirm对话框进行确认,用户如果OK,发生postback,如果Cancel掉,就停留在原页面不做任何操作,类似于我们在删除按钮上添加的客户端功能。此时,便事不由人了……
我们准备两个页面。在Default.aspx中,加入文本框、按钮,设置按钮跨页回送到Target.aspx:
<
asp:TextBox
ID
="TextBox1"
runat
="server"
></
asp:TextBox
>
<
asp:Button
ID
="Button1"
runat
="server"
Text
="Cross Page Post Back"
PostBackUrl
="~/Target.aspx"
OnClientClick
="return confirm('Are u sure?')"
/>
在Target.aspx.cs中,Find到Default.aspx里的TextBox,把值显示在Label上:
protected
void
Page_Load(
object
sender, EventArgs e)
{
if
(PreviousPage
!=
null
)
Label1.Text
=
(PreviousPage.FindControl(
"
TextBox1
"
)
as
TextBox).Text;
}
运行,然后发现当我们点击Cancel的时候,确实可以Cancel掉,但是点OK,却无论如何都无法将请求发出去了。
到底是什么原因使得跨页请求无法提交呢?大概和我们加入的OnClientClick="return confirm('Are u sure?')"有关,因此我们查看一下浏览器里ASP.NET为了达到Cross-Page Postback效果而生成的源代码:
<
input
name
="TextBox1"
type
="text"
id
="TextBox1"
/>
<
input
type
="submit"
name
="Button1"
value
="Cross Page Post Back"
onclick
="return confirm('Are u sure?');WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("Button1", "", false, "", "Target.aspx", false, false))"
id
="Button1"
/>
原来跨页回送依靠的是在submit之前,调用一个JavaScript的WebForm_DoPostBackWithOptions()函数,而我们所需要的return confirm()被加在了该函数调用的前面,因此,如果confirm()方法返回false,就return false了,不会有任何动作,而用户点OK按钮,confirm()返回true的话,相当于onclick="return true;",于是后面的WebForm_DoPostBackWithOptions()函数就无法调用了。
分析清楚了原因,再来找解决办法。在界面上弹出confirm对话框,必须用return cofirm()这一种方法么?既然confirm()方法的返回值是个bool类型,我们是否能把它放到if语句里呢?我们是否能把onclick里的调用改成if (confirm()) { doSomething(); }这种形式呢?
我们来改写按钮:
OnClientClick="if (confirm('Are u sure?')) "
测试后发现,点Cancel的时候却发生了Cross-Page Postback。
<
input
name
="TextBox1"
type
="text"
id
="TextBox1"
/>
<
input
type
="submit"
name
="Button1"
value
="Cross Page Post Back"
onclick
="if (confirm('Are u sure?')) ;WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("Button1", "", false, "", "Target.aspx", false, false))"
id
="Button1"
/>
原因是ASP.NET会自动在我们的JavaScript语句后加上分号,所以,我们可以反过来写:
OnClientClick="if (confirm('Are u sure?')) return false;"
此时跨页回送完全可以达到我们的预期了。浏览器中生成的代码为:
<
input
name
="TextBox1"
type
="text"
id
="TextBox1"
/>
<
input
type
="submit"
name
="Button1"
value
="Cross Page Post Back"
onclick
="if (!confirm('Are u sure?')) return false;WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("Button1", "", false, "", "Target.aspx", false, false))"
id
="Button1"
/>
以上,我们解决了在使用Cross-Page Postback机制时可能遇到的小问题。问题虽小,但想引起初学者注意的是解决问题的方法。编程经验从哪儿来呢?其实就是来自于解决问题的思路,而解决问题的思路又来自于对我们所储备知识的灵活应用。以上解决方案中涉及的知识点,大概作为初学者都已储备,剩下的其实就是需要我们在实际编程环境中通过思考、尝试,去积极寻找解决之道。在此借用一句烂俗的话:没有解决不了的问题。
接下去,我们是不是可以通过这种方式,自行去研究一下Cross-Page Postback的工作机制呢?这个在ASP.NET 1.1版没有,在2.0才加入的机制,是不是真有什么神奇之处呢?
首先,我们只看到了对WebForm_DoPostBackWithOptions()函数的调用,因此需要找到该函数的定义。通过查看客户端的源代码,我们并没有发现该函数的定义,但是找到了一个<script>标签,引用了一个外部的WebResource.axd文件:
<
script
src
="/CrossPagePostBack/WebResource.axd?d=ZOvwxDkQx08x9P6zrcQviA2&t=633694239333996679"
type
="text/javascript"
></
script
>
我们将src中的虚拟路径粘贴到浏览器的地址栏,回车,浏览器会提示下载该WebResource.axd文件。将文件下载后,用文本文档打开。其中第一个function就是参数WebForm_PostBackOptions(),第二个function就是WebForm_DoPostBackWithOptions()了。我们可以看到WebForm_PostBackOptions()的第5个参数actionUrl,在被调用的时候用的是"Target.aspx",也就是"Target.aspx",双引号被编码了而已。而WebForm_DoPostBackWithOptions对actionUrl做了些什么呢?
if
((
typeof
(options.actionUrl)
!=
"
undefined
"
)
&&
(options.actionUrl
!=
null
)
&&
(options.actionUrl.length
>
0
)) {
theForm.action
=
options.actionUrl;
}
其实也就是将actionUrl设置给了表单(即<form name="form1" method="post" action="Default.aspx" id="form1">,在Default.aspx的客户端代码里可以找到var theForm = document.forms['form1'];)的action属性。这下就清楚了吧!ASP.NET的WebForm机制默认每个页面的表单数据以HTTP POST方法提交给页面自己(action="Default.aspx"为自动生成,自行修改也没用),称为Postback。而Cross-Page Postback,不就是允许将POST请求提交到别的action么!其本质也就是利用JavaScript,在submit之前(函数末尾调用了__doPostBack()函数)去修改表单元素的action属性。
这下,对Cross-Page Postback机制是不是清楚了很多?顺着这样的思路,我们可以经常自己去分析一下ASP.NET Framework到底为我们准备好了哪些,它们是如何工作的,该如何让它们为我们所用,该如何去扩展改进它们,让它们更好的为我们工作。
Enjoy!