views:

804

answers:

2

Edit: Now I need to solve this problem for real, I did a little more investigation and came up with a number of things to reduce duplicate content. I posted detailed code samples on my blog: Reducing Duplicate Content with ASP.NET MVC

First post - go easy if I've marked this up wrong or tagged it badly :P

In Microsoft's new ASP.NET MVC framework it seems there are two things that could cause your content to be served up at multiple URLs (something which Google penalize for and will cause your PageRank to be split across them):

  • Case-insensitive URLs
  • Default URL

You can set the default controller/action to serve up for requests to the root of your domain. Let's say we choose HomeController/Index. We end up with the following URLs serving up the same content:

  • mydomain.com/
  • mydomain.com/Home/Index

Now if people start linking to both of these then PageRank would be split. Google would also consider it duplicate content and penalize one of them to avoid duplicates in their results.

On top of this, the URLs are not case sensitive, so we actually get the same content for these URLs too:

  • mydomain.com/Home/Index
  • mydomain.com/home/index
  • mydomain.com/Home/index
  • mydomain.com/home/Index
  • (the list goes on)

So, the question... How do I avoid these penalties? I would like:

  • All requests for the default action to be redirected (301 status) to the same url
  • All URLs to be case sensitive

Possible?

+1  A: 

As well as posting here, I emailed ScottGu to see if he had a good response. He gave a sample for adding constraints to routes, so you could only respond to lowercase urls:

public class LowercaseConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route,
            string parameterName, RouteValueDictionary values,
            RouteDirection routeDirection)
    {
        string value = (string)values[parameterName];

        return Equals(value, value.ToLower());
    }

And in the register routes method:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "home", action = "index", id = "" },
        new { controller = new LowercaseConstraint(), action = new LowercaseConstraint() }
    );
}

It's a start, but 'd want to be able to change the generation of links from methods like Html.ActionLink and RedirectToAction to match.

Danny Tuppeny
+7  A: 

I was working on this as well. I will obviously defer to ScottGu on this. I humbly offer my solution to this problem as well though.

Add the following code to global.asax:

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    // If upper case letters are found in the URL, redirect to lower case URL.
    if (Regex.IsMatch(HttpContext.Current.Request.Url.ToString(), @"[A-Z]") == true)
    {
        string LowercaseURL = HttpContext.Current.Request.Url.ToString().ToLower();

        Response.Clear();
        Response.Status = "301 Moved Permanently";
        Response.AddHeader("Location",LowercaseURL);
        Response.End();
    }
}

A great question!

Gabe
This has a potential downside, as far as I can tell. Open Chrome (or another browser that has good debugging capabilities) and notice that all requests for images, stylesheets, javascript etc are redirected (assuming you have them in a folder called 'Content' or whatever.) You don't want the browser to have to double the number of requests for assets like these, so either ensure they're lowercase, or don't send 301s for links that aren't actually routes.
Drew Noakes