I received an email today and was asked why UpdatePanel would cause problems if it was combined with UrlRewrite. I didn't take it seriously at first, because I have also used UpdatePanel in UrlRewrite before, and there was no problem. However, after receiving the packaged code from the other party, I found that the problem had indeed recurred. If I accessed the target page directly, there would be no problem. Because I was in the company at the time and did not carefully study the cause of the error. On the way home, I simulated the implementation process of UpdatePanel over and over again in my mind, but I didn't notice anything wrong. In the end, I couldn't help myself. I opened my laptop while sitting on the bus and carefully searched for the problem. The bus was shaking really hard, but luckily I finally found the problem before I vomited. My thinking just now was still wrong.
Reproducing the problem:
Now I will reproduce the problem. NBear's UrlRewriteModule was used in the original code. For the sake of simplicity, I used the most common UrlRewrite method to get the same effect, trying to avoid some friends (including me) who are not familiar with NBear and hinder the understanding of the article content.
First, create a new ASP.NET AJAX Enabled Web Site. Create a file ~/SubFolder/Target.aspx with the following content:
~/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>
Then create a Global.asax, provide the Application_BeginRequest method, and implement Url Rewrite in it, as follows:
Application_BeginRequest method in Global.asax
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);
}
}
In this way, when we access the ~/Source.aspx file, it will be Rewritten to ~/SubFolder/Target.aspx, open the page, and everything is normal:
After clicking the Refresh button, the time is updated. Then when we clicked the button again, the error occurred: "Sys.WebForms.PageRequestManagerServerErrorException: An unknown eror occurred while processing the request on the server. The status code returned from the server was: 12031".
Analysis of the problem:
The reason for this problem is that Url Rewrite updates the address submitted by the Form, and UpdatePanel reflects the change in the address to the page.
When we open the page for the first time, we can see that the action of the <form /> element in the source file of the page is no longer the Source.aspx we accessed, but the target file after Url Rewrite:
The action of the form element is the target page
...
<form name="form1" method="post" action="SubFolder/Target.aspx" id="form1">
...
</form>
...
Fortunately, we use Partial Rendering. As long as the "target" is correct, UpdatePanel can still send and get data correctly, and then update the page. Therefore, after clicking the Refresh button, the page is updated correctly. However, the action of our form element has also changed, which can be seen at a glance using Web Development Helper and IE Dev Toolbar:
Since we directly accessed ~/SubFolder/Target.aspx when performing asynchronous PostBack, the action value of the generated Form object is Target.aspx. As a result, UpdatePanel diligently modified the action of the client form element. This will allow us to access a non-existent page when we submit again, and errors are inevitable.
Solve the problem:
Now that you have discovered the problem, you will naturally be able to solve it easily. We only need to respond to the load event of Sys.Application. It will be triggered when the page is loaded for the first time and after each Partial Rendering. At this time, we can modify the action attribute of the form element in the page, as follows:
Corresponding Sys.Application load event
Sys.Application.add_load(function()
{
var form = Sys.WebForms.PageRequestManager.getInstance()._form;
form._initialAction = form.action = window.location.href;
});
As for why the form element in the page should be obtained in this way, what _initialAction is, and why it should be set, it involves the implementation of UpdatePanel, so I won’t explain it here. As long as such a small piece of code is placed on the page, this problem is solved.
In-depth question:
The reason for this problem is actually that after Url Rewrite, the action of the form element is not the address requested by the client, but the target address of Url Rewrite. If we do not use Partial Rendering, but use the most traditional PostBack, although the page function will not be damaged, after PostBack, the user will find that the content of the address bar has changed and directly becomes the target address. This is not the result we want to see. Now that it has been rewritten, let’s rewrite it to the end. Of course, we can still use the method mentioned above and use JavaScript to modify the action of the form element, but this method is not "beautiful" enough, and the user can also see the target address of our Url Rewrite from the HTML source file, not ?
It would be great if we could set the Form's action on the server side, but unfortunately the System.Web.UI.HtmlControls.HtmlForm class does not allow us to do this. But fortunately, we use ASP.NET, and we use the object-oriented programming model. So we "inherit" System.Web.UI.HtmlControls.HtmlForm and implement our own Form control:
inherit the HtmlForm class to implement our own 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);
}
}
}
Then we can use it in the page. Of course, before that, we need to register it in the page (or Web.config):
use our own implemented Form
<%@ Register TagPrefix="skm" Namespace="ActionlessForm"
Assembly="ActionlessForm" %>
...
<skm:Form id="Form1" method="post" runat="server">
...
</skm:Form>
...
At this point, we no longer need to write a "clever" JavaScript in the page. The action problem of the form element after Url Rewrite is solved.
("In-depth questions" refer to part of the previous article on 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