Serve extensionless URL from ASP.NET without using ISAPI module or IIS 6 Wildcard mapping

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 VPS, you cannot do this. 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.

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. This means IIS receives the request but it serves the page configured for HTTP 404. It does not send the request to ASP.NET ISAPI. 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 on HTTP 404.

Benefits of this approach:

  • No thirdparty ISAPI module required
  • No Wildcard mapping thus no performance sacrifice

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".

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: }

 

11 Comments

  • Don't forget to mention that in the case of no redirects you have to set also response code to 202. Otherwise server treats it still as error condition and IE with friendly error messages may show it's internal error message instead.

    But this solution seems okay :)

  • DigiMortal,

    Great feedback. This is a great blog post. Thanks Omar!

  • You could even just compile that into a simple assembly and add it as an HttpModule.

    Also, you may consider checking for a period first, before you do any of the splitting and querystring parsing. That way it will find out if the URL is bad much sooner, saving server overhead.

  • Or you could use an HttpModule designed for this, such as UrlRewriting.net, this allows you some great flexibility such as using regexp's to parse URL's, passing various parameters etc.

    Plus, it doesn't break 404 handling.

    It's a fairly neat trick though, but if you can get access to IIS to setup 404's, you can easily enable the use of a rewriting HttpModule

  • I'm trying to use this solution, which in theory works great. Unfortunately, I'm not getting this to work with IIS 5.0 or 5.1. Whenever IIS redirects to the ASPX page, it's serving the source. The page displays properly when accessed directly or when reached through a web.config customError redirect. It's just IIS that's being difficult. Any ideas on how to get around that?

  • I'm confused. This doesn't work for me - I get the extensionless URL redirecting to the 404.aspx page (using IIS6) but there's no query string as my page is just being bounced from IIS's custom error handling straight to /404.aspx.

    A bad URL with a .aspx extension gets passed through just fine, but that's because I'm handling the custom errors for those in the web.config file.

    Am I missing something?

  • This looks great.

    Is there a way to configure VS.NET to debug this? How can I tweak the 404 error in the studio web server on XP?

  • great ideas, some minor issue thou:

    line 3 HttpContext.Current.Request.Url.AbsolutePath;
    should be HttpContext.Current.Request.Url.AbsoluteUri;

    you might also want add .ToLower() before doing any string comparision.

  • Interessante Informationen.

  • It does not work for me
    it gives 404.
    i have done settings for 404 on iis6.
    and put the code in global.asax
    but it does not seems to be worked.

  • Hi. When i tried this solution and checked my C:/Windows/System32/Logfiles it shows me 403 instead of 404. Earlier it used to give me 404. Can some one explain me why this happened?

Comments have been disabled for this content.