ASP.NET MVC - Routing of Legacy URLs

 
9/22/2009
.NET, ASP.NET, C#, MVC
7 Comments

When you convert an existing ASP.NET application to ASP.NET MVC you will sooner or later want to handle legacy URLs.
Imagine an ASP.NET application containing the page "YourPage.aspx".
Now you want to redirect request to that legacy URL to the new MVC Action: "Home/YourPage".

I have looked at several implementations on the internet, but none of them was really simple.
Thus I implemented another solution which is really easy to configure.

For the URL "YourPage.aspx" (see above) you only have to add one line to your Global.asax.cs:

routes.Add(new LegacyRoute("YourPage.aspx", "Home/YourPage"));

Quite simple, isn’t it? But what happens behind the scenes? Let’s have a look at the source:

The class LegacyRoute derives from Route and its constructor takes a second argument "target", which will be the RedirectLocation:

public class LegacyRoute : Route
{
  public LegacyRoute(string url, string target)
      : base(url, new LegacyRouteHandler())
  {
      this.Target = target;
  }

public string Target { get; private set; }

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { return null; }
}

The constructor in LegacyRoute uses LegacyRouteHandler, this class simply creates instances of LegacyHandler:

public class LegacyRouteHandler : IRouteHandler
{
  public IHttpHandler GetHttpHandler(RequestContext requestContext) 
  {
      return new LegacyHandler(requestContext);
  }
}

And finally the LegacyHandler which is responsible for the redirect:

public class LegacyHandler : MvcHandler
{
  public LegacyHandler(RequestContext requestContext) 
      : base(requestContext) 
  {
  }

protected override void ProcessRequest(HttpContextBase httpContext) { var legacyRoute = RequestContext.RouteData.Route as LegacyRoute;

  httpContext.Response.Status = "301 Moved Permanently";
  httpContext.Response.RedirectLocation = legacyRoute.Target;

} }

Now if you call "YourPage.aspx" the LegacyRoute matches the request. Instead of the regular MVCHandler a LegacyHandler redirects the request to "Home/YourPage".

I have attached the full source code including a demo website so you see the above code in action.

Updates

07.01.2011: In Visual Studio 2010/.NET 4.0 the ProcessRequest of the LegacyHandler never gets executed. Use the following code to get it working again:

public class LegacyHandler : MvcHandler
{
  public LegacyHandler(RequestContext requestContext) 
      : base(requestContext) 
  {
  }

  protected override System.IAsyncResult BeginProcessRequest(HttpContext httpContext, System.AsyncCallback callback, object state)
  {
    var legacyRoute = RequestContext.RouteData.Route as LegacyRoute;

    httpContext.Response.Status = "301 Moved Permanently";
    httpContext.Response.RedirectLocation = legacyRoute.Target;
    httpContext.Response.End();

    return null;
  }
}

Downloads

Feedly Feedly Tweet


Related posts


Comments


Daniel

Daniel

12/21/2012

@baris: I just tried it on my machine and on my public webserver and it works as expected. I always get a 301 response. My website is hosted in IIS.


baris

baris

12/21/2012

When I debug with Fiddler. First Time it redirects and send back 301 header. But after the first use it redirects but no 301 header. When we want to use for Seo purposes Google bot should receive always 301 header. We should send back 301 everytime. I didn't understand whether MVC or Server uses some caching. Can we make something to always send back 301. Thank you.


seishin

seishin

9/29/2011

Great! As David wrote your solution is the simplest and works :) Thanks for that. I made a minor change in the LegacyHandler to pass the query string further to the controller: httpContext.Response.RedirectLocation = legacyRoute.Target + (httpContext.Request.QueryString != null ? "?" + httpContext.Request.QueryString.ToString() : string.Empty);


Paul Adrian

Paul Adrian

7/23/2011

Thank you for this tutorial and for putting up the full code for VS2010. I'm new to this and it's very helpful to study a running copy. And the wildcard fix worked beautifully. One question: In MVC3 is there a way to use named routes instead of the target URL? So, from the example, instead of "Home/YourPage" you could use "MyMapRouteName" defined elsewhere in your Global.asax?


Daniel

Daniel

6/17/2011

@Carlton: Try that route: routes.Add(new LegacyRoute("Products/{*sub}", "Products.aspx")); In LegacyHandler change the line that sets the RedirectLocation: httpContext.Response.RedirectLocation = HttpRuntime.AppDomainAppVirtualPath + legacyRoute.Target; That should work in your case.


Carlton Fletcher

Carlton Fletcher

6/17/2011

Hi, this works really well for specific legacy routes, but is there a way of handling a generic wildcard route? For example, at a folder level? We replaced a classic asp site with new MVC site, but are getting a load of old referal links from external sites, or customer bookmarks. So where we might have had a products folder with sub-folders, and we want them all to re-routed to say a generic "product.aspx" page?


David McQuiggin

David McQuiggin

4/12/2010
http://www.manatix.com

Very nice. I had also looked at several implementations of similar but more complex solutions on the web, and could not use the IIS7 Url Rewrite module for various reasons. Your solution is the simplest I have found to date using Routing - it just works. Thanks for going the extra mile to include a demo with source code - that is always appreciated.