程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> UpdatePanel與UrlRewrite

UpdatePanel與UrlRewrite

編輯:.NET實例教程
今天收到郵件,被問及為什麼UpdatePanel如果結合了UrlRewrite就會出現問題。一開始我不以為然,由於我也曾經在UrlRewrite時使用過UpdatePanel,沒有出現過問題。但是收到對方打包的代碼後,發現這個問題的確重現了,如果直接訪問目標頁面就不會有任何問題。因為當時在公司,沒有仔細地去研出錯的原因。在回家的路上,腦子裡一遍一遍地模擬著UpdatePanel的實現過程,卻沒有察覺到有任何不妥。最後還是忍不住,坐在公交車上的時候就打開筆記本,仔細的尋找問題所在。公交車實在晃得厲害,還好最終在我嘔吐之前找到了問題,剛才的思考還是棋差一著。


重現問題:

  現在我將重現那個問題。在原來的代碼中使用了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)
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved