UpdatePanel与UrlRewrite
点击次数:19 次 发布日期:2008-11-26 11:34:57 作者:源代码网
|
源代码网推荐 源代码网推荐 源代码网推荐 重现问题: 源代码网推荐 源代码网推荐 现在我将重现那个问题。在原来的代码中使用了NBear的UrlRewriteModule,为了简单起见,我使用了最普通的UrlRewrite的做法来得到相同的效果,尽量避免有些朋友(包括我)因为不熟悉NBear而妨碍文章内容的理解。 源代码网推荐 源代码网推荐 首先,新建一个ASP.NET Ajax Enabled Web Site。创建一个文件~/SubFolder/Target.aspx,内容如下: 源代码网推荐 源代码网推荐 ~/SubFolder/Target.aspx 源代码网推荐 <html xmlns="http://www.w3.org/1999/xhtml" > 源代码网推荐 <head runat="server"> 源代码网推荐 <title>Target Page</title> 源代码网推荐 </head> 源代码网推荐 <body> 源代码网推荐 <form id="form1" runat="server"> 源代码网推荐 <asp:ScriptManager ID="ScriptManager1" runat="server"> 源代码网推荐 </asp:ScriptManager> 源代码网推荐 源代码网推荐 <asp:UpdatePanel ID="UpdatePanel1" runat="server"> 源代码网推荐 <ContentTemplate> 源代码网推荐 <%= DateTime.Now.ToString() %> 源代码网推荐 <asp:Button ID="Button1" runat="server" Text="Refresh" /> 源代码网推荐 </ContentTemplate> 源代码网推荐 </asp:UpdatePanel> 源代码网推荐 </form> 源代码网推荐 </body> 源代码网推荐 </html> 源代码网推荐 源代码网推荐 源代码网推荐 然后再创建一个Global.asax,提供Application_BeginRequest方法,在其中实现Url Rewrite,如下: 源代码网推荐 源代码网推荐 Global.asax中Application_BeginRequest方法 源代码网推荐 void Application_BeginRequest(object sender, EventArgs e) 源代码网推荐 { 源代码网推荐 HttpContext context = (sender as HttpApplication).Context; 源代码网推荐 if (context.Request.Path.Contains("Source.aspx")) 源代码网推荐 { 源代码网推荐 context.RewritePath("SubFolder/Target.aspx", false); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 这样,当我们访问~/Source.aspx文件时,则会被Rewrite至~/SubFolder/Target.aspx,打开页面,一切正常: 源代码网推荐 源代码网推荐 源代码网推荐 点击Refresh按钮之后,时间被更新了。然后当我们再点击按钮之后,错误发生了:“Sys.WebForms.PageRequestManagerServerErrorException: An unknown eror occurred while processing the request on the server. The status code returned from the server was: 12031”。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 分析问题: 源代码网推荐 源代码网推荐 发生这个问题的原因是因为Url Rewrite更新了Form提交的地址,而UpdatePanel又将这地址的改变反映到了页面上。 源代码网推荐 源代码网推荐 在第一次打开页面时,我们可以看到页面的源文件中<form />元素的action已经不是我们访问的Source.aspx,而是Url Rewrite后的目标文件: 源代码网推荐 源代码网推荐 form元素的action为目标页面 源代码网推荐 ... 源代码网推荐 <form name="form1" method="post" action="SubFolder/Target.aspx" id="form1"> 源代码网推荐 ... 源代码网推荐 </form> 源代码网推荐 ... 源代码网推荐 源代码网推荐 还好我们使用了Partial Rendering,只要“目标”是正确的,UpdatePanel依旧能够正确地发送和获取数据,然后更新页面。因此,在点击Refresh按钮之后,页面被正确更新了。可是,我们form元素的action也变了,使用Web Development Helper和IE Dev Toolbar便一目了然: 源代码网推荐 源代码网推荐 源代码网推荐 由于我们在进行异步PostBack时,直接访问了~/SubFolder/Target.aspx,因此在生成的Form对象其action值为Target.aspx。于是乎,UpdatePanel兢兢业业地将客户端form元素的action也进行了修改。这样就让我们再次提交时访问了一个不存在的页面,错误就再所难免了。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 解决问题: 源代码网推荐 源代码网推荐 既然发现了问题所在,那么解决起来自然也会得心应手。我们只要在响应Sys.Application的load事件即可,它会在页面第一次加载时,以及每次Partial Rendering之后被触发,我们在这时候修改页面中form元素的action属性即可,如下: 源代码网推荐 源代码网推荐 相应Sys.Application的load事件 源代码网推荐 Sys.Application.add_load(function() 源代码网推荐 { 源代码网推荐 var form = Sys.WebForms.PageRequestManager.getInstance()._form; 源代码网推荐 form._initialAction = form.action = window.location.href; 源代码网推荐 }); 源代码网推荐 源代码网推荐 至于为什么应该这样获得页面中的form元素,_initialAction又是什么,以及为什么要设置它,就要牵涉到UpdatePanel的实现方式,在这里就不多作解释了。只要页面中放置了这么一小段代码,这个问题就被解决了。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 深入问题: 源代码网推荐 源代码网推荐 造成这个问题的原因,其实就是因为在Url Rewrite之后,form元素的action并非客户端请求的地址,而是Url Rewrite的目标地址。如果我们没有使用Partial Rendering,而是使用了最传统的PostBack,虽然不会造成页面功能的破坏,但是在PostBack之后,用户就会发现地址栏的内容变了,直接变成了目标地址。这可不是我们希望看到的结果,既然Rewrite了,就把它Rewrite到底。当然,我们依然可以使用上面提到的办法,使用javascript来修改form元素的action,但是这个做法实在不够“美观大方”,而且用户从HTML源文件中也可以看到我们Url Rewrite的目标地址,不是吗? 源代码网推荐 源代码网推荐 如果我们能够在服务器端设置Form的action就好了,可惜System.Web.UI.HtmlControls.HtmlForm类不允许我们这么做。不过还好,我们用的是ASP.NET,我们用的是面向对象的编程模型。于是我们“继承”System.Web.UI.HtmlControls.HtmlForm,实现一个自己的Form控件: 源代码网推荐 源代码网推荐 继承HtmlForm类实现自己的From 源代码网推荐 namespace ActionlessForm { 源代码网推荐 public class Form : System.Web.UI.HtmlControls.HtmlForm 源代码网推荐 { 源代码网推荐 protected override void RenderAttributes(HtmlTextWriter writer) 源代码网推荐 { 源代码网推荐 writer.WriteAttribute("name", this.Name); 源代码网推荐 base.Attributes.Remove("name"); 源代码网推荐 writer.WriteAttribute("method", this.Method); 源代码网推荐 base.Attributes.Remove("method"); 源代码网推荐 this.Attributes.Render(writer); 源代码网推荐 base.Attributes.Remove("action"); 源代码网推荐 if (base.ID != null) 源代码网推荐 writer.WriteAttribute("id", base.ClientID); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 然后我们就可以在页面中使用它了。当然,在这之前,我们需要在页面(或Web.config)里注册它: 源代码网推荐 源代码网推荐 使用我们自己实现的Form 源代码网推荐 <%@ Register TagPrefix="skm" Namespace="ActionlessForm" 源代码网推荐 Assembly="ActionlessForm" %> 源代码网推荐 ... 源代码网推荐 <skm:Form id="Form1" method="post" runat="server"> 源代码网推荐 ... 源代码网推荐 </skm:Form> 源代码网推荐 ... 源代码网推荐 源代码网推荐 源代码网推荐 至此,我们已经不需要在页面里编写一段“巧妙”的JavaScript了,Url Rewrite之后form元素的action问题被解决了。 源代码网推荐 源代码网推荐 (“深入问题”参考了MSDN上一篇文章的部分内容:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp) 源代码网推荐 http://www.cnblogs.com/JeffreyZhao/archive/2006/12/27/updatepanel_with_url_rewrite.html 源代码网推荐 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
