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,却无论如何都无法将请求发出去了。




删除 overlay2 不使用的_javascript


到底是什么原因使得跨页请求无法提交呢?大概和我们加入的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的话,相当于οnclick="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,在被调用的时候用的是&quot;Target.aspx&quot;,也就是"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!