< rewriter >
< rewrite url = " ^/User/(d+)$ " to = " ~/User.aspx?id=$1 " processing = " stop " />
< rewrite url = " ^/User/(w+)$ " to = " ~/User.aspx?name=$1 " processing = " stop " />
</ rewriter >
When the user requests "/User/jeffz", the code that appears on the page will be <form action="/User.aspx?name=jeffz" />. This is because when the code is generated, the page The current value of Request.Url.PathAndQuery will be used to get the action of the form element. This causes "User.aspx?name=jeffz" to appear in the address bar once PostBack, and this address may not be able to request the correct resource (because it may be rewritten elsewhere, or due to directory level relationships) There is no such resource). In the previous article " UpdatePanel and UrlRewrite ", I said that this problem can be solved by adding a line of JavaScript code at the end of the page:
< script language ="javascript" type ="text/javascript">
document.getElementsByTagName( "form" )[0].action = window.location;
</script> The purpose
of this line of code is very obvious. Change the action of the form to window.location (that is, the path in the browser address bar), so that when the page performs PostBack, the target address will be the address before URL Rewrite. . This approach can make the program run normally, but it really doesn't satisfy me. Why?
Because it's too ugly.
Because we still expose the address after URL Rewrite to the client. As long as the user installs an HTTP sniffer (such as the famous Fiddler), or directly selects to view the source file in IE, our target address will be displayed in front of the user without any concealment. How can we let users know our rewriting rules? We must solve this problem. The solution is very simple and already very popular, which is to use Control Adapter to change the behavior of Form generation. But what makes me feel strange is that all the searches for this Control Adapter on the Internet are VB.NET versions, but the C# language mainly promoted by Microsoft cannot be found. Although it is not difficult to rewrite as long as you understand a little bit of VB.NET syntax, it is still extra work after all. So I will post the C# version code of this Adapter now so that friends can use it directly:
namespace Sample.Web.UI.Adapters
{
public class FormRewriterControlAdapter :
System.Web.UI.Adapters.ControlAdapter
{
protected override void Render( HtmlTextWriter writer)
{
base .Render( new RewriteFormHtmlTextWriter (writer));
}
}
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
public RewriteFormHtmlTextWriter( HtmlTextWriter writer)
: base (writer)
{
this .InnerWriter = writer.InnerWriter;
}
public RewriteFormHtmlTextWriter( TextWriter writer)
: base (writer)
{
this .InnerWriter = writer;
}
public override void WriteAttribute( string name, string value, bool fEncode)
{
if (name == "action" )
{
HttpContext context = HttpContext .Current;
if (context.Items[ "ActionAlreadyWritten" ] == null )
{
value = context.Request.RawUrl;
context.Items[ "ActionAlreadyWritten" ] = true ;
}
}
base .WriteAttribute(name, value, fEncode);
}
}
}
To put it simply, this Control Adaptor has actually been waiting for the moment when the "action" attribute is output, and changes the value to the RawUrl attribute of the current Request object. This attribute is determined when ASP.NET first receives the request from IIS. It will not change with the subsequent Rewrite operation in BeginRequest. Therefore, we only need to output the RawUrl for the Form action to solve the PostBack address change problem. Problem.
However, for this Control Adapter to take effect, you must also create a browser file in the Web project, such as "App_BrowsersForm.browser", and write the following code in it:
< browsers >
< browser refID = " Default " >
<controlAdapters>
< adapter controlType = " System.Web.UI.HtmlControls.HtmlForm "
adapterType = " Sample.Web.UI.Adapters.FormRewriterControlAdapter " />
</ controlAdapters >
</ browser >
</ browsers >
At this point, the problem of PostBack address changes caused by URL Rewrite at the ASP.NET level has been perfectly solved - wait, why should we emphasize the "ASP.NET level"? That's right, because if you do URL Rewrite on the IIS level, this problem still exists. For example, if you use IIRF for URL Rewrite and enable the above Control Adapter, you will still find that the PostBack address on the page is different from the address requested by the client. Has RawUrl also become "disloyal"? This is not due to RawUrl, but is determined by the ASP.NET mechanism. In order to explain this problem, let's take a look again at the diagram in the first article " IIS and ASP.NET ":
IIS-level URL Rewrite occurs before step 2 in the above picture. Because it is rewritten, the ISAPI selector of IIS will hand over the request to ASPNET ISAPI for processing. In other words, when IIS hands the request to the ASP.NET engine for processing, the information ASP.NET obtains from IIS is already the address after URL Rewrite (for example, /User.aspx?name=jeffz), so no matter No matter where ASP.NET processes the request, it cannot know the URL when IIS received the request.
In other words, there is really nothing we can do about it.
However, the four words "there is really no way" are conditional. To put it completely, it should be: "relying on ASP.NET itself" is indeed "there is no way". But what if IIS helps us when performing URL Rewrite? As a mature open source component, IIRF naturally knows that the ASP.NET engine and even all ISAPI handlers need its help. It naturally knows the principle of "make changes when you make changes", so it has learned to store the original address. Capabilities in the server variable HTTP_X_REWRITE_URL. However, IIRF will not do this "consciously" (how tiring), so we need to remind it in the configuration file:
RewriteRule ^/User/(d+)$ /User.aspx?id=$1 [I, L , U]
RewriteRule ^/User/(w+)$ /User.aspx?name=$1 [I, L, U]
Please note that we use an additional Modifier. Adding U to the Modifier collection indicates that we need IIRF to store the original address before URL Rewrite in the server variable HTTP_X_REWRITE_URL. Now we can get this value in ASP.NET, so we modify the WriteAttribute method in the previous Control Adapter code as follows:
public override void WriteAttribute( string name, string value, bool fEncode)
{
if (name == "action" )
{
HttpContext context = HttpContext .Current;
if (context.Items[ "ActionAlreadyWritten" ] == null )
{
value = context.Request.ServerVariables[ "HTTP_X_REWRITE_URL" ]
?? context.Request.RawUrl;
context.Items[ "ActionAlreadyWritten" ] = true ;
}
}
base .WriteAttribute(name, value, fEncode);
}
Now the value of the action is not simply obtained from the RawUrl attribute, but tries to obtain the value of the HTTP_X_REWRITE_URL variable from the ServerVariables collection, because the address of the original request received by IIS is stored there.
At this point, the main topics about URL Rewrite have been covered. In the next article, which is the last article in this series, we will focus on the differences in some details caused by using different levels of URL Rewrite, and Relevant points of note.