Search Engine Optimization guides, recommends to have one version of a URL of the same content. Search engines may pickup www and non-www versions of URL as 2 separate URLs, i.e. http://xyz.com/page1 may be considered different to http://www.xyz.com/page1. It is a good idea to pick on of these URLs as preferred and use 301 redirects to send traffic from the other URLS to the preferred URL. Today we will pickup www version of URL as our preferred URL and look at how we can redirect the non-www version of the URL to our preferred URL structure using ASP.NET MVC.
We can achieve the above by writing a custom handler that extends from the MvcHandler. We are basically interested in the ProcessRequest method where we can get hold of the non-www version of the URL to replace it to the www. version of URL.
public class The301GlobalHandler : MvcHandler
{
public The301GlobalHandler(RequestContext requestContext) : base(requestContext) { }
protected override void ProcessRequest(HttpContextBase httpContext)
{
//We do not want this handler to process local requests
if (httpContext.Request.IsLocal)
base.ProcessRequest(httpContext);
else
ProcessExternalRequest(httpContext);
}
private void ProcessExternalRequest(HttpContextBase httpContext)
{
bool urlChanged = false;
string url = RequestContext.HttpContext.Request.Url.AbsoluteUri;
//Check for non-www version URL
if (!RequestContext.HttpContext.Request.Url.AbsoluteUri.Contains("www"))
{
urlChanged = true;
//change to www. version URL
url = url.Replace("http://", "http://www.");
}
ProcessExternalRequest(url, urlChanged, httpContext);
}
private void ProcessExternalRequest(string url, bool urlChanged, HttpContextBase httpContext)
{
if (urlChanged)
{
//mark as 301
httpContext.Response.Status = "301 Moved Permanently";
httpContext.Response.StatusCode = 301;
httpContext.Response.AppendHeader("Location", url);
}
else
base.ProcessRequest(httpContext);
}
}
The above code is self explanatory, we are checking if the Request is local or external, we are only interested on external URLs. Next we check, whether the RequestContext.HttpCOntext.Request.Url.AbsoluteUri contains a "www" or not. If it do not contain a "www" we go and inject a "www" to the URL to convert the non-www version of URL to a www. version URL. Then we mark the previous response to a 301, which indicates that the previous URL has been permanently removed and all future requests should be directed to the given new URL.
We have developed our core handler above, however we need a wrapper IRouteHandler class to get the above The301GlobalHandler to work within the MVC Framework. This wrapper class is responsible to return an instance of the The301GlobalHandler.
public class Route301GlobalHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new The301GlobalHandler(requestContext);
}
}
We have got our Route301GlobalHandler ready, now we need all of our requests to go via this handler instead of the default. One easy way to do this, is to iterate through the route collection and assign them to this Route301GlobalHandler during the Application_Start().
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
Route301Global.ReAssignHandler(RouteTable.Routes);
}
public static class Route301Global
{
public static void ReAssignHandler(RouteCollection routes)
{
using (routes.GetReadLock())
{
AssignRoute301GlobalHandler(routes);
}
}
private static void AssignRoute301GlobalHandler(IEnumerable<RouteBase> routes)
{
foreach (var routeBase in routes)
{
AssignRoute301GlobalHandler(routeBase);
}
}
private static void AssignRoute301GlobalHandler(RouteBase routeBase)
{
var route = routeBase as Route;
if (route == null) return;
if (route.RouteHandler.GetType() != typeof(Route301Handler))
route.RouteHandler = new Route301GlobalHandler();
}
}
Note, if you have other custom RouteHandler in your application, you will need to tweak this code, I am assuming all routes that will be mapped in the RegisterRoutes(RouteCollection routes) method uses the MvcHandler.
Conclusion
We have identified keeping one set of URL is important for SEO. Then we have looked at how we can 301 redirect non-www version of URL to www. version URL in ASP.NET MVC. Hope this saves you some time and thank you for being with me so far.