Click here to Skip to main content
Click here to Skip to main content

IIS vs. ASP.NET URL Rewriting

By , 23 Nov 2009
 

Introduction

It is important for web sites to have user friendly URLs, it helps search engine optimization and improves user-experience. In ASP.NET, nice URLs can be achieved by using URL rewriting, but deployment of such applications may be annoying. The problem is that when IIS receives a request like mydomain.com/products/3, it does not use ASP.NET to process it. Instead, IIS tries to find the file products/3 in the website folder and returns error 404 to the client. Unfortunately, there is no elegant solution, but an ugly one does exist.

Solution concept

If you have full control over the server where your application is hosted, you are lucky - it is enough to make all requests processed by the same DLL which processes .aspx files. Unfortunately, it is not always possible. For example, when virtual hosting or IIS 5 is used. So there is plan B. We configure the website to use error404.axd as the error 404 page URL. When a request like mydomain.com/products/3 is received, IIS will use ASP.NET to open error404.axd?http://mydomain.com/products/3. This allows us to use URL rewriting and fix up the URL.

Solution code

public class Error404RewritingModule : IHttpModule
{
  private static readonly FieldInfo HttpMethodFieldInfo;
  private static readonly FieldInfo HttpVerbFieldInfo;
 
  public void Init(HttpApplication context)
  {
    context.BeginRequest += OnBeginRequest;
  }
 
  static void OnBeginRequest(object sender, EventArgs e)
  {
    HttpContext httpContext = HttpContext.Current;
    HttpRequest httpRequest = httpContext.Request;
    //
    string targetPath = httpRequest.AppRelativeCurrentExecutionFilePath;
    if (!targetPath.StartsWith("~/Error404.axd", 
               StringComparison.InvariantCultureIgnoreCase))
      return;
 
    Uri requestedUrl = httpRequest.Url;
    var currentApplicationUrl = new Uri(requestedUrl, httpRequest.ApplicationPath);
    //
    // Extract initially requested url
    string initiallyRequestedUrl = ExtractInitiallyRequestedUrl(requestedUrl.Query);
    string initiallyRequestedQuery = ExtractInitiallyRequestedQuery(initiallyRequestedUrl);
    string initiallyRequestedVirtualPath = GetInitiallyRequestedVirtualPath(
      currentApplicationUrl, initiallyRequestedUrl);

    if (String.IsNullOrEmpty(initiallyRequestedQuery)) 
      httpContext.RewritePath("~/Hack", "/", "a=b", true);
         
    if (!String.Equals(httpRequest.HttpMethod, "POST", 
                 StringComparison.InvariantCultureIgnoreCase))
       if (httpRequest["__VIEWSTATE"] != null || 
           httpRequest["__EVENTTARGET"] != null) {
        HttpMethodFieldInfo.SetValue(httpRequest, "POST");
        HttpVerbFieldInfo.SetValue(httpRequest, 5); // 5 = POST
      }

    httpContext.RewritePath(initiallyRequestedVirtualPath, null, "", true);    
  }
...
}

There are two interesting places; the first is the following:

if (String.IsNullOrEmpty(initiallyRequestedQuery)) 
   httpContext.RewritePath("~/Hack", "/", "a=b", true);

It would take a deep diving into ASP.NET internals to explain this, but the reason is the following. If the query string is empty, then HttpRequest.Current.Url is not changed by rewriting sometimes. The second place of interest is:

if (!String.Equals(httpRequest.HttpMethod, "POST", 
            StringComparison.InvariantCultureIgnoreCase))
  if (httpRequest["__VIEWSTATE"] != null || httpRequest["__EVENTTARGET"] != null) {
    HttpMethodFieldInfo.SetValue(httpRequest, "POST");
    HttpVerbFieldInfo.SetValue(httpRequest, 5); // 5 = POST
  }

It is required because IIS 6.0 passes a GET request to Error404.axd, even if the client sends POST. So this code hacks HttpRequest to make it POST again.

Usage

  • Place Xtensive.Web.Deployment.dll in the bin folder of your application and add the following to the httpModules configuration section:
  • <httpModules>
       <add name="LiveUI.Error404-Handler" 
           type="Xtensive.Web.Error404RewritingModule, Xtensive.Web">
    </httpModules>
  • Configure the website to use error404.axd as the error 404 (error 405) page URL. If you use IIS, it will look like this:
  • If you use virtual hosting, it will look like this:

Conclusion

You might not like the solution presented, neither do I, but it is better than nothing. Initially, I developed this module to help LiveUI users to deploy their applications, so it was tested on LiveUI demos. But there should be no problems in using it with other frameworks such as ASP.NET MVC or UrlRewriting.NET.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alexandr Sergeevich Ilyin
Software Developer Xtensive
Russian Federation Russian Federation
Member
I've been working at Xtensive company for 3 years.
My current project is LiveUI web framework which should make everybody happy. If I can be of any help to you feel free to contact me alexandr.ilyin at gmail.com.
 
By the way, I have a blog.


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe redirection to Login.aspxmemberAjay Kale New9 Sep '10 - 2:48 
Hi
 
I have a query regarding redirection to Login page, which I am not being able to trace out.
 
When I click on any of the tab in my application (which internally loads a new aspx page) sometimes it
is redirected to Login.aspx, which is unexpected. Couldnot debug why this is happening even by javascript alerts and C# debugging statements.
 
Below is the view source piece from Login.aspx, just for clue
<form name="Form1" method="post" action="login.aspx?ReturnUrl=%2fValuations%2fToDoList.aspx" id="Form1">
 
Valuations is the dll of application and ToDoList.aspx is the tab page I clicked which should load, but suddenly Login.aspx page is displayed. I traced the complete solution project.
 
Can you please help me...?
 
- Ajay K
GeneralRe: Re redirection to Login.aspxmemberAlexandr Sergeevich Ilyin9 Sep '10 - 6:37 
Hello, I can suggest the following way to figure out what's happening. Get mozilla firefox and firebug plugin. Then find __DoPostback function in rendered html and place breakpoint there (using firebug). That will give you postback event arguments. Moreover firebug will show you http traffic which usually helps a lot. If it will not help, contact me using email.
GeneralRe: Re redirection to Login.aspxmemberAjay Kale New9 Sep '10 - 23:35 
Hi Alexandr
 

the markup given
 
<form name="Form1" method="post" action="login.aspx?ReturnUrl=%2fValuations%2fToDoList.aspx" id="Form1">
 
is of the login-page which is finally displayed unexpectedly, and we have no-where set such form-action in application so as to redirect to login.aspx.
 
And I have used tabs UI control in my application where I click around and if kept any page in the tab idle for sometime(may it be 2-5-10-15 mins), and clicks on another tab link in the application, it suddenly redirects to Login.aspx page.I saw the view source of that login page and pasted above.
 
please help...
 
- Ajay K
GeneralWhere is " ~/Error404.axd"memberyaya rabiu david17 Aug '10 - 23:30 
I have followed the instructions in this article but now i'm getting 404 for ~/Error404.axd. Is there a configuration I still need to do to make the httpmodule work???
GeneralRe: Where is " ~/Error404.axd"memberAlexandr Sergeevich Ilyin18 Aug '10 - 6:39 
Hello, No additional configuration is needed. Error404.axd url is used just to make request processed by ASP.NET. Suggested solution might fail because of Virtual directories. For example, if your asp.net application hosted in MyDerectory then you should use /MyDirectory/Error404.axd as an error url.
 
PS: Usually this trick works, thought, I've once faced the situation when it did not work at Windows Server 2003 and I failed to find out why.
GeneralThere IS elegant solution(at least in .NET 3.5 SP1)memberSelvin24 Nov '09 - 2:30 
namespace: System.Web.Routing
sample here[^]
 
...works fascinates me...i can stare it for hours...

GeneralRe: There IS elegant solution(at least in .NET 3.5 SP1)memberAlexandr Sergeevich Ilyin24 Nov '09 - 3:32 
May be I am wrong, but it seems to me that whatever routing we use, IIS will ignore it because it ignores ASP.NET (for requests like products/1).
GeneralRe: There IS elegant solution(at least in .NET 3.5 SP1)memberzivni2 Dec '09 - 19:57 
You can tell IIS 6.0 to forward all requests to asp.net
In IIS 7 it easier.
Look at MVC tutorial for examples http://www.asp.net/learn/mvc/tutorial-08-cs.aspx[^]
GeneralRe: There IS elegant solution(at least in .NET 3.5 SP1)memberAlexandr Sergeevich Ilyin3 Dec '09 - 5:58 
Of course, it is. I am talking about virtual hosting and IIS 5.
GeneralRe: There IS elegant solution(at least in .NET 3.5 SP1)membermkeeton7 Dec '09 - 0:27 
OK, I might be being really thick here but how do I set my web app to use the 404error.axd when I'm debugging the app. During debugging VS uses the development web server and I can't find the setting to make it use the 404error so that I can debug my re-routing.
GeneralRe: There IS elegant solution(at least in .NET 3.5 SP1)memberAlexandr Sergeevich Ilyin7 Dec '09 - 8:56 
Indeed, when development web server is used all requests are processed by ASP.NET so you can't debug re-routing. I would recommend to install IIS locally and use it for debugging (look at project properties in Visual studio)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 23 Nov 2009
Article Copyright 2009 by Alexandr Sergeevich Ilyin
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid