Problem

If you want to serve extensionless URL from ASP.NET 2.0 like the following:

  • www.store.com/books
  • www.store.com/books/asp.net2.0
  • www.forum.com/post/how-to-serve-extensionless-url

You cannot, unless you use some third party ISAPI module or use IIS 6.0 Wildcard mapping feature. Third party ISAPI module needs to be installed on the server directly. If you don't have a dedicated server or a Virtual Private Server where you can install an ISAPI module, you cannot take this approach. Moreover ISAPI modules intercept each and every request, so the more modules you install, the slower each request becomes. On the other hand, IIS 6.0 Wildcard mapping makes each and every request go through ASP.NET 2.0 ISAPI handler including Urls with .gif, .css, .js, .html etc. So, it suffers from scalability problem. Some independent research shows there's 30% drop in performance in IIS 6.0 when you use wildcard mapping. So, this is not a good solution either.

Solution

Here's an approach which works without using ISAPI module or wildcard mapping in IIS 6.0. When you request extensionless URL, you get HTTP 404 page. This means IIS receives the request and it serves the page configured for HTTP 404. Generally this is a 404.html file that resides in IIS directory. IIS does not send the request to ASP.NET handler and thus you cannot intercept 404 requests. So, if you can forward all HTTP 404 to ASP.NET, you can serve such extensionless URL. In order to forward HTTP 404 to ASP.NET ISAPI, all you need to do is configure IIS to redirect to some .aspx extension when a missing extensionless url is hit.

Benefits of this approach:

  • No thirdparty ISAPI module required. Thus no installation problem, no request interception delay
  • No Wildcard mapping thus no performance sacrifice for ASP.NET

Here's how to configure 404 redirection in IIS 6.0:

On IIS 6.0 change 404 default page to /404.aspx and the type to "URL". On IIS 7.0, change 404 default page to /404.aspx and the type to "ExecuteURL". Also, change the default error response to "Custom error pages".

iis7.png

When you will request an URL like "www.shop.com/products/books" it will redirect to "www.shop.com/404.aspx?404;http://www.shop.com/products/books". From Global.asax BeginRequest event, capture this URL and see whether it's an extensionless URL request. If it is, do your URL rewriting stuff for such extensionless URL.

   1: protected void Application_BeginRequest(object sender, EventArgs e)
   2: {
   3:     string url = HttpContext.Current.Request.Url.AbsolutePath;
   4:
   5:     // HTTP 404 redirection for extensionless URL or some missing file
   6:     if (url.Contains("404.aspx"))
   7:     {
   8:         // On 404 redirection, query string contains the original URL in this format:
   9:         // 404;http://localhost:80/Http404Test/OmarALZabir
  10:
  11:         string[] urlInfo404 = Request.Url.Query.ToString().Split(';');
  12:         if (urlInfo404.Length > 1)
  13:         {
  14:             string originalUrl = urlInfo404[1];
  15:
  16:             string[] urlParts = originalUrl.Split('?');
  17:
  18:             string queryString = string.Empty;
  19:             string requestedFile = string.Empty;
  20:
  21:             if (urlParts.Length > 1)
  22:             {
  23:                 requestedFile = urlParts[0];
  24:                 queryString = urlParts[1];
  25:             }
  26:             else
  27:             {
  28:                 requestedFile = urlParts[0];
  29:             }
  30:
  31:             if( requestedFile.IndexOf('.') > 0 )
  32:             {
  33:                 // There's some extension, so this is not an extensionless URL.
  34:                 // Don't handle such URL because these are really missing files
  35:             }
  36:             else
  37:             {
  38:                 // Extensionless URL. Use your URL rewriting logic to handle such URL
  39:                 // I will just add .aspx extension to the extension less URL.
  40:                 HttpContext.Current.RewritePath(requestedFile + ".aspx?" + queryString);
  41:             }
  42:         }
  43:     }
  44: } 

The above code finds the virtual directory name e.g. /omar that was requested but resulted in HTTP 404. From the redirected URL, it parses and finds the missing folder name. From there, it rewrites the folder to a .aspx file extension which can handle the request for the missing URL. You can do different actions like rewrite to Default.aspx with the query parameters, redirect to another page and so on.

We have used this approach in Pageflakes. You can visit URLs like www.pageflakes.com/omar and get the URL handled by our homepage.

This solution is search engine friendly because no one ever sees a HTTP 404. You can test this using tools like Fiddler and see the missing URL hit will not produce HTTP 404 or any redirect. The response header will be HTTP 200 and the rewritten page content will appear as response body. So, there's no issue with search engine optimization (SEO).

Things to watch out

Missing graphics, CSS and javascript

Browser thinks the missing URL is a folder and thus requests all relative files (graphics, css, js) from that URL. So, if you have a graphics at images/test.gif location of your site and you visit www.pageflakes.com/omar URL, then browser will request the graphics from www.pageflakes.com/omar/images/test.gif location.

Solution is to use a <base> tag and specify the correct location from where all relative URL is fetched. For ex, you can set <base href="http://www.pageflakes.com/">. This will force browser to assume the page is being served from the root folder and thus translate all relative URL from the root URL. So, the graphics URL will be translated to www.pageflakes.com/images/test.gif which is the correct URL.

Postback reveals ugly URL

Another problem is related to postback. When you rewrite to an .aspx page, the form tag will be generated based on the .aspx page's path, not the path from where the url was rewritten. For example, rewriting to somepage.aspx will render a form tag where the action attribute is set to somepage.aspx. So, a postback will redirect the browser to somepage.aspx.

You can use Scott Gu's solution from here: http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx

AJAX Stops working

When AJAX framework does not download from proper URL and async postbacks go to different URL than you intended, such problems happen. So, you need to use the <base> tag to produce the correct URL from where AJAX frameworks need to be downloaded and then rewrite form action tag to make async postbacks go to correct URL.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"