ASP.NET MVC: Maintaining URL Permanence with Legacy Routes

What makes a cool URI?
A cool URI is one which does not change.
What sorts of URI change?
URIs don’t change: people change them.

– Tim Berners-Lee, creator of the interwebs

While working on our current ASP.NET MVC 3 project, we came across a requirement to maintain a large directory of .htm files that were used as content generated by users of the website.  While blowing off the dust and looking inside of the files we realized that there we lots of URLs that are supposed to be active pages.  Some of these were locations of images that were moving, while others were old ASP pages that are still redirected and even still register is the top 10 of search results for their associated keywords.  Immediately one of our developer’s heads began pounding with the pain of regular expression string replacement.

But wait!  These are permanent URLs that still have active SEO functionality.  Our client needs these links to stay active and not 404 their way into irrelevance.  Plus, it would be a pain to either:

  1. Go through each HTM file and string replace as many combinations we can find, or
  2. Use string replace each and every time we try to load the file

Enter Routing made easy with ASP.NET MVC 3.

First, we had to make sure the linked images in these files still display images when loaded up in the browser.  Most are located at the address:

<img src="" />

..or something similar.  However, with the new design these images no longer lived at this physical location.  Hmm . . . to the Routes!

                new { controller = "Image", action = "Feature" }

Okay, great you defined a route.  But how do you give an image as a “View”?  Well, thankfully in ASP.NET MVC there is a FilePathResult.

public ActionResult Feature(string filename)
            return File("~/content/images/features/" + filename, "image/jpeg");

public class ImageController : Controller
        public ActionResult Feature(string filename)
             return File("~/content/images/features/" + filename, "image/jpeg");

There is also the option to actually create a stream and return a FileStreamResult as well, but this lets us do the same without having to open/close a stream reader.

So now that we have the image URL out of the way, what about those legacy ASP/ASPX routes that will no longer be valid?  And how can we do it without losing SEO value that our client has built up over the years?  Hmm . . . to the Routes!

Imagine we have the legacy route “/feature/showFeature.asp?fid={id}”

                new { controller = "Features", action = "BackwardsCompatibleDetail" }

And so the legacy route is now generated and matched, but how to handle that query string parameter?  Well you can define those in the Routing, but they are passed on as Nullable parameter objects to your methods on your controllers.

public ViewResult BackwardsCompatibleDetail(int? fid)
            return View("Detail", _repository.GetById(eid.GetValueOrDefault()));

And there you go!  You’re legacy route is now generated in the new MVC route table!

So that’s great and all, but what I really want is for those URLs to no longer be generated and instead just issue 301 redirects to the new URL path for this resource.  Phil Haack (Best. Name. Ever.) comes to the rescue with his RouteMagic library, available I might add via NuGet.  His example:

var route = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
routes.Redirect(r => r.MapRoute("old", "foo/{controller}/{action}/{id}"))

And the best part is a lot of this Routing framework is extendible, so we can create our own handlers and such to do even more complex things with the Routing.  But out of the bag, there are plenty of options with dealing with your SEO URL permanence and making sure those continue to bring in the traffic you need.  Viva Routing + MVC!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: