eWorld.UI - Matt Hawley

Ramblings of Matt

ASP.NET MVC - Legacy Url Routing

April 25, 2008 00:47 by matthaw
In addition to blogging, I'm also using Twitter. Follow me @matthawley

Recently, we've been converting over a lot of our ASP.NET Web Form pages to use ASP.NET MVC. While this is no small feat by itself, the underlying problem of having a new Url structure in the site while still supporting legacy Url's was necessary. The idea, is that you hit a page that no longer exists, and you get redirected to the appropriate controller & action within MVC.



  1. A legacy Url is requested from your site. For example, http://www.server.com/Users/Login.aspx
  2. ASP.NET routing intercepts the request and matches a route from your route collection
  3. Instead of using the MvcRouteHandler, a LegacyRouteHandler is invoked.
  4. Using the LegacyRouteHandler, it'll use the route redirection name you specified, generate the MVC Url, and issue a HTTP 301 with the location of http://www.server.com/site/login.


First, we should define our legacy route class. This is necessary because we need to expose an additional property to enable our routing handler to find the correct MVC route.

   1: // The legacy route class that exposes a RedirectActionName
   2: public class LegacyRoute : Route {
   3:     public LegacyRoute(string url, string redirectActionName, IRouteHandler routeHandler)
   4:         : base(url, routeHandler)
   5:     {
   6:         RedirectActionName = redirectActionName;
   7:     }
   9:     public string RedirectActionName { get; set; }
  10: }

Secondly, we need to define the route handler and associated http handler. The route handler derives from IRouteHandler, and will be the class used when creating your legacy routing. The http handler derives from MvcHandler because it gives us some critical information, like RequestContext. You'll also notice that (while not in the code) you need to copy all of the querystring parameters from the request over. This is a necessary step because the GetVirtualPath method call will take all route data (from RouteData.Values) and try and utilize that when building the Url itself.

   1: // The legacy route handler, used for getting the HttpHandler for the request
   2: public class LegacyRouteHandler : IRouteHandler {
   3:     public IHttpHandler GetHttpHandler(RequestContext requestContext) {
   4:         return new LegacyHandler(requestContext)
   5:     }
   6: }
   8: // The legacy HttpHandler that handles the request
   9: public class LegacyHandler : MvcHandler {
  10:     public LegacyHandler(RequestContext requestContext) : base(requestContext) { }
  12:     protected override void ProcessRequest(HttpContextBase httpContext) {
  13:         string redirectActionName = ((LegacyRoute)RequestContext.RouteData.Route).RedirectActionName;
  15:         // ... copy all of the querystring parameters and put them within RouteContext.RouteData.Values
  17:         VirtualPathData data = RouteTable.Routes.GetVirtualPath(RouteContext, redirectActionName, RouteContext.RouteData.Values);
  19:         httpContext.Status = "301 Moved Permanently";
  20:         httpContext.AppendHeader("Location", data.VirtualPath);
  21:     }
  22: }

Lastly, you need to create your routes within the Global.asax file. Remember, that order is necessary when setting up routing.

   1: public void RegisterRoutes(RouteCollection routes) {
   2:     routes.MapRoute("Login", "site/login", new {
   3:         controller = "Users",
   4:         action = "DisplayLogin"
   5:     });
   7:     routes.Add("", new LegacyRoute(
   8:         "Users/Login.aspx",
   9:         "Login",
  10:         new LegacyRouteHandler()));
  11: }

And that's it. When a request comes in, you'll see the following in Fiddler

  1. A request on "Users/Login.aspx"
  2. A HTTP 301, with a header "Location" and value of "site/login"
  3. A request on "site/login"

Final Thoughts

Granted, there's more you can do with this - like creating your own extension methods like MapRoute and doing better handling of finding the route, but this should get you started. Also, I'm writing the code off the top of my head, so there's no guarantee that any of it works as-is. Please let me know if you have any other thoughts.


Lastly, for those wondering why are we using a HTTP 301 status code? Well read up on them. "301 Moved Permanently" indicates "that all future requests should be directed to the given URI." While your end users will not see any difference other than a new URL in the browser, the 301 status code more aimed towards search engines to update their URL's in their indexes.


Click here to download the source code for this example.


kick it on DotNetKicks.com


May 3. 2008 07:54

Pingback from weblogs.asp.net

ASP.NET MVC - Legacy Url Routing - eWorld.UI - Matt Hawley


May 6. 2008 18:22

Pingback from code-inside.de

Wöchentliche Rundablage: ASP.NET MVC, Silverlight 2, jQuery, CSS, C#… | Code-Inside Blog


May 15. 2008 12:59

Pingback from hsidev.wordpress.com

ASP.NET MVC Resources « HSI Developer Blog


October 9. 2008 16:27

Pingback from ytechie.com

ASP.NET MVC, What about SEO?


October 18. 2008 04:22

Pingback from feeds.feedburner.com

Scott Hanselman's Computer Zen - ASP.NET MVC and the new IIS7 Rewrite Module


October 18. 2008 04:23

Pingback from hanselman.com

Scott Hanselman's Computer Zen - ASP.NET MVC and the new IIS7 Rewrite Module


December 26. 2008 13:32

Here is my scenario.  For the example lets say that I need to return a list of cars based on a search criteria.  I would like to have a single View to display the results since the output will be the same, but I need several ways of getting there.  For instance, I may have a Form with a textbox to search by year.  I may have another separate page that contains a hyperlink for all red, Toyota cars.  How do I handle these multiple scenarios in the same View and Controller.  My dilemma is that the search could contain several options… year, make, model, etc but I don’t know where to put them.

What is the best approach for this?  Should I define the parameters in the routing or go with query strings, etc?

Eric Brown

February 21. 2009 09:03

Pingback from msdnbangladesh.net

ASP.NET MVC tips: Routing Engine to aid SEO / 301 Redirect / Tracking - Shahed


February 21. 2009 09:05

Pingback from msmvps.com

ASP.NET MVC tips: Routing Engine to aid SEO / 301 Redirect / Tracking - Shahed Khan (MVP C#)


February 21. 2009 09:05

Pingback from msbdusers.net

Shahed Khan (MVP C#) : ASP.NET MVC tips: Routing Engine to aid SEO / 301 Redirect / Tracking


March 28. 2009 05:17

This is great.. 1 question though could i use this for requests like http://www.server.com/Users/Login.html . So with file extensions html. Cause i have couple of really old links pointing to a site of mine

Bayram Çelik

June 5. 2009 06:12

thanks nice info...


June 30. 2009 02:32

Pingback from dbones.co.uk

A Little more on the MVC Routing


October 9. 2009 03:26

The problem is that the ASP.NET MVC default routing is too forgiving. ... old style urlMapping section in the web.config for legacy URL's. ...
<a href="www.profitbysearch.com/...india.html">Link Building India</a> | <a href="http://www.profitbysearch.nl/">Zoekmachine optimalisatie</a> | <a href="http://www.dataentryindia.net/">Data Entry India</a> |  <a href="http://www.neswebdesign.com/">Web Design India</a> |  <a href="www.searchengine-optimization.net/">Search Engine Optimization </a> |  <a href="www.offshoresoftwaredevelopmentindia.net/">Offshore Software Development India</a> |  <a href="http://www.in-sitedesigns.com/">Web Design India</a>


February 5. 2010 12:37

Pingback from weblogs.asp.net

Using IIS Rewriting with MVC Routes to Keep Your Routes Simple - Jon Galloway


July 14. 2010 23:34

Pingback from topsy.com

Twitter Trackbacks for
        ASP.NET MVC - Legacy Url Routing
        on Topsy.com


Comments are closed

Copyright © 2000 - 2024 , Excentrics World