Blog Post

301 Redirects in ASP.NET MVC (SEO and Refactoring)

Ideas & Innovation
301 Redirects in ASP.NET MVC (SEO and Refactoring)
  • 08
    Sep
  • Image

301 Redirects in ASP.NET MVC (SEO and Refactoring)


Building a website is usually an iterative process. Not many individuals or teams have build a website without having requirements change along the way (If you have then I would like to know the secret). When requirements change sometimes this will require refactoring of the application to elegantly satisfy the business needs.

Some of the refactoring will include url/routes changes leaving many of your previous url/routes returning 404 errors. This is of course a definite no no! If you asked the question why, then here is the answer. After a search engine has indexed your website it remembers those urls/routes and serves them up in the search results. Whenever a user clicks through they either get a 404 error or redirected to another friendly not found page. Now ask yourself this, how often have you clicked through from a search engine and offered a page other than the one you requested and you remained on the website (if you remained longer than 5 seconds then this article is not for you)? The problem doesn't just end there. Imagine you have written a wonderful article and posted it on your wesbite/blog. Your readers have found this article very useful and decided to share it with their friends, then you go and change the url/route (possibly by altering the title); now this article cannot be found from wherever around the internet this url has been shared.

Just a few of the negatives:

  1. Reduced traffic
  2. Broken Links
  3. Unhappy search engines possibly resulting in lower ranking
  4. Diminished reputation.

An elegant and simple solution:

	/// 
	/// Base http response result
	/// 
	public class HttpResponseResult : ActionResult
	{
		#region Overrides of ActionResult

		public override void ExecuteResult(ControllerContext context)
		{}

		#endregion
	}
	/// 
	/// 301 redirect
	/// 
	public class PermanentRedirectResult : HttpResponseResult
	{
		private string _url { get; set; }

		public PermanentRedirectResult(string url)
		{
			_url = url;
		}

		#region Overrides of ActionResult

		public override void ExecuteResult(ControllerContext context)
		{
			context.HttpContext.Response.Status = "301 Moved Permanently";
			context.HttpContext.Response.StatusCode = 301;
			context.HttpContext.Response.AddHeader("Location", _url);
			context.HttpContext.Response.Flush();
			context.HttpContext.Response.End();
		}

		#endregion
	}

Now the last and critical part of the entire solution. How do you use the PermanentRedirectResult class. Very simple.

	public class RedirectsController : Controller
	{
		// Map the old path to this action
		public ActionResult DefaultPage()
		{ 
			// Take action
			return new PermanentRedirectResult(Url.Action("Index", "Home"));
		}
		
		// You can even redirect Html pages
		// Simple map the route including the name of the page (somepage.htm)
		private ActionResult HtmlPage()
		{
			return new PermanentRedirectResult(Url.Action("SomePage", "Products"));
		}
	}

Please feel free to post your comments.

Comments (4)

phil gainley 10 September 2010, 12:38 PM Website

another great post



liked how you have a default action for pages that no longer exists

Richard Lee 12 September 2010, 12:49 AM

Purely coincidental having the action called DefaultPage. Just simply demonstrating the principle of handling 404 responses. Ideally you should redirect to the new location of the page the user is looking for, but what happens when the page no longer exists? I suppose you can redirect to the landing page for the particular section of the website.

Michiari 17 May 2012, 07:08 PM Website

Nice post, Hatim! Excellent explanation, and sthrigat to the point.I would add one caveat about using WindowsIdentity.GetCurrent() to get user credentials in an application. That function doesn't necessarily return information about the logged in user all the time. Rather, it returns the ID of the user that's currently running the app thread.Where I've seen issues happen with using WindowsIdentity.GetCurrent to get the user's credentials is if a developer tries to use WindowsIdentity.GetCurrent to get the logged in user on a web application. In the application that I saw, it returned the NT Authority\Network Service (ID running the thread) rather than the actual user on the application.I was very happy that you mentioned in your post that ASP.NET app users should use HttpContext.Current.User to get the login information about the user on the application.

Salma 19 May 2012, 04:13 AM Website

UngerYes. I've recently been using a wapeprr class to contain functions and properties that access the HttpContext.I use an interface to make the wapeprr class passable into my service and data access layers. The service/data access classes only need to know about the interface (not that it uses HttpContext), so my service/data access layers are not tightly coupled to MVC.I guess it depends on where you need to use the full URL, but either a wapeprr class or extension method sounds like a good place to me! Great suggestion!

New Comment

Notify me of follow up posts