views:

2880

answers:

8

I'm using URL rewrite on my site to get URLs like:
http://mysite.com/users/john
instead of
http://mysite.com/index.aspx?user=john

To achive this extensionless rewrite with IIS6 and no access to the hosting-server I use the "404-approach". When a request that the server can't find, the mapped 404-page is executed, since this is a aspx-page the rewrite can be performed (I can setup the 404-mapping using the controlpanel on the hosting-service).

This is the code in Global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
 string url = HttpContext.Current.Request.Url.AbsolutePath;
 if (url.Contains("404.aspx"))
 {
  string[] urlInfo404 = Request.Url.Query.ToString().Split(';');
  if (urlInfo404.Length > 1)
  {
   string requestURL = urlInfo404[1];
   if (requestURL.Contains("/users/"))
   {
    HttpContext.Current.RewritePath("~/index.aspx?user=" + GetPageID(requestURL));    
    StoreRequestURL(requestURL);
   }
   else if (requestURL.Contains("/picture/"))
   {
    HttpContext.Current.RewritePath("~/showPicture.aspx?pictureID=" + GetPageID(requestURL));
    StoreRequestURL(requestURL);
   }
  }
 }
}

private void StoreRequestURL(string url)
{
 url = url.Replace("http://", "");
 url = url.Substring(url.IndexOf("/"));
 HttpContext.Current.Items["VirtualUrl"] = url;
}

private string GetPageID(string requestURL)
{
 int idx = requestURL.LastIndexOf("/");
 string id = requestURL.Substring(idx + 1);
 id = id.Replace(".aspx", ""); //Only needed when testing without the 404-approach
 return id;
}

And in Page_Load on my masterpage I set the correct URL in the action-attribute on the form-tag.

protected void Page_Load(object sender, EventArgs e)
{
    string virtualURL = (string)HttpContext.Current.Items["VirtualUrl"];
    if (!String.IsNullOrEmpty(virtualURL))
    {
     form1.Action = virtualURL;
    }
}

The rewrite works fine but when I perform a postback on the page the postback isn't executed, can this be solved somehow?

The problem seems to be with the 404-approach because when I try without it (and loses the extensionless-feature) the postback works. That is when I request:
http://mysite.com/users/john.aspx

Can this be solved or is there any other solution that fulfil my requirements (IIS6, no serveraccess/ISAPI-filter and extensionless).

+3  A: 

Scott Guthrie covers different ways of doing this here without IIS access:

http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx

Personally, I've created HTTPModules in the past and it's pretty easy to put together.

brendan
Yes I have read that ScottGu-article, didn't think you could get HttpModules to execute from extensionless-URLs using IIS6... I will look into that.
salle55
Doesn't seem possible without ISAPI, Scott writes:"IIS 5/6 makes it hard to perform URL rewriting on these types of URLs (extensionless) within ISAPI Extensions (which is how ASP.NET is implemented). Instead you need to perform the rewriting earlier in the IIS request pipeline using an ISAPI Filter"
salle55
+1  A: 

I would start by installing Live Http Headers and see whats going on with the Http requests.

Ahh here in that article it explains it, looks like the action attribute of the form tag is wrong:

One gotcha that people often run into when using ASP.NET and Url-Rewriting has to-do with handling postback scenarios. Specifically, when you place a <form runat="server"> control on a page, ASP.NET will automatically by default output the "action" attribute of the markup to point back to the page it is on. The problem when using URL-Rewriting is that the URL that the control renders is not the original URL of the request (for example: /products/books), but rather the re-written one (for example: /products.aspx?category=books). This means that when you do a postback to the server, the URL will not be your nice clean one.

With ASP.NET 1.0 and 1.1, people often resorted to sub-classing the <form> control and created their own control that correctly output the action to use. While this works, it ends up being a little messy - since it means you have to update all of your pages to use this alternate form control, and it can sometimes have problems with the Visual Studio WYSIWYG designer.

The good news is that with ASP.NET 2.0, there is a cleaner trick that you can use to rewrite the "action" attribute on the <form> control. Specifically, you can take advantage of the new ASP.NET 2.0 Control Adapter extensibility architecture to customize the rendering of the <form> control, and override its "action" attribute value with a value you provide. This doesn't require you to change any code in your .aspx pages. Instead, just add a .browser file to your /app_browsers folder that registers a Control Adapter class to use to output the new "action" attribute...

Shawn Simon
I don't think the action is the problem, as you can see in my code I update the action-attribute to the "virtualURL" using the new feature in .NET 3.5 SP1. And when I run without the 404-approach (use .aspx in the end of the URL) the postback works fine with the same action-updating-code.
salle55
A: 

Anyone? I'm starting to think this isn't possible without IIS7 or ISAPI-filter.

salle55
A: 

The problem is within the 404 handling. Your form is posting to a non-exising page, ASP.NET redirects the request to the 404 page and so it loses all the postback data.

The only solution is to set the form's action attribute to the existing page, so users will see the index.aspx?user=john when they submit the form. For SEO this would not be a problem, since crawlers don't issue posts and therefore do not see the ugly address.

Ronald
A: 

You could just use the below instead:

form1.Action = Request.RawUrl

I'm not sure what that would be in C#, but this is what it is in VB and it works a treat

Richard Wallace
+1  A: 

form1.Action = Request.RawUrl is also how it is written in C# put it in the page load method

Paul
A: 

try something like this:

            if (Request.HttpMethod == "GET" && shouldChangeUrl)
            {
                urlRedirect = "REAL-URL-HERE";

                _postBackUrl = urlRedirect;
                Context.RewritePath(urlRedirect);
            }
            else
                //If Post Back (Request.HttpMethod="POST")
                Context.RewritePath(_postBackUrl);

So, you save the real URL for the postback in a variable (here: _postBackUrl) when rewriting the url and then use it only when postback.

Toma
+1  A: 
form1.Action = Request.RawUrl

in combination with

HttpContext.Current.RewritePath("/Default.aspx", true); 

works very well for me.

setting the form Action attribute was the piece i was missing...

Thanks for the solution!!!

Simon Rückert
+1. I know the question is rather old now, but this answer works in my experience. Incidentally, this fix is necessary any time are doing postback in combination with RewritePath; I encountered it when using the "urlMapping" feature of ASP.NET 2.0, where the path is being rewritten by the framework.
harpo