Canonical URL’s for ASP.NET MVC

The aim of this post is to give your site better search engine rankings using special Search Engine Optimization (SEO) techniques. Take a look at the URL’s below and see if you can spot the differences between them:

  1. http://example.com/one/two/
  2. https://example.com/one/two/
  3. http://example.com/one/two
  4. http://example.com/One/Two

The second one has a HTTPS scheme, the third omits the trailing slash and the fourth has mixed case characters. All of the URL’s point to the same resource but it turns out that search engines treat every one of these URL’s as unique and different. Search engines give each URL a page rank, which determines where the resource will show up in the search results. Another term you will also hear quite often is ‘link juice’. The link juice conceptualizes how page rank flows between pages and websites.

If your site exposes the above four different URL’s to the single resource, your link juice is being spread against each one and as a result, that will be having a detrimental impact on your page rank.

The Canonical Link Tag

One way to solve this problem is to add a canonical link tag to the head of your HTML page. This tells search engines what the canonical (actual) URL to the page is. The link tag contains a URL to your preferred URL for the page.

One thing you must decide early on is your preferred URL for every page. You must ask yourself the following questions and use the resulting URL in your canonical link tag.

  1. Do I prefer this page to be HTTP or HTTPS? This is yet another reason to go with HTTPS across your entire site.
  2. Should the URL end with a trailing slash? This is often preferred over omitting it but it’s a matter of preference.
  3. Should I allow a mix of upper-case and lower-case characters? Most sites choose to go with all lower-case characters.

When search engines follow a link to your page, regardless of which URL they followed to get to your page, all of the link juice will be given to the URL specified in your canonical link tag. Google goes into a lot more depth about this tag here.

301 Permanent Redirects

Unfortunately, using the canonical link tag is not the recommended approach. The intention is that it should only be used to retrofit older websites, so they can become optimized for search engines.

According to both Google and Bing, the recommended approach if you visit a non-preferred format of your pages URL is to perform a 301 permanent redirect to the preferred canonical URL. According to them, you only lose a tiny amount of link juice by doing a 301 permanent redirect.

Canonical URL’s in MVC

ASP.NET MVC (5 and 6) have two settings you can use to automatically create canonical URL’s every time you generate URL’s.



Once you apply these settings and are using the UrlHelper to generate all your URL’s, you will see that across your site all URL’s are lower-case and all end with a trailing slash (This is just my personal preference you may not like trailing slashes).

This means that within your site, no 301 permanent redirects to canonical URL’s are required because the URL’s are already canonical. However, this just solves part of the problem. What about external links to your site? What happens when people copy and paste your site and delete or add a trailing slash? What happens when someone types in a link to your site and puts in an upper-case character? The fact is you have no control over external links and when search engine crawlers follow those non-canonical links you will be losing valuable link juice.

301 Permanent Redirects in MVC

Enter the RedirectToCanonicalUrlAttribute. This is an MVC filter you can apply, which will check that the URL from each request is canonical. If it is, it does nothing and MVC returns the view in its response as normal. If the URL is not canonical, it generates the canonical URL based on the above MVC settings and returns a 301 permanent redirect response to the client. The client can then make another request to the correct canonical URL.

You can take a look at the source code for the RedirectToCanonicalUrlAttribute, NoTrailingSlashAttribute and NoLowercaseQueryStringAttribute’s (I shall explain in a minute) for MVC 5 below or the MVC 6 version here. You can also get it from the ASP.NET MVC Boilerplate Framework NuGet package for MVC 5 or MVC 6.

Adding the RedirectToCanonicalUrlAttribute filter is easy. You can add it to the global filters collection so all requests will be handled by it like so:

That’s it! It’s as simple as that! Now there are two special cases, which is where the NoTrailingSlashAttribute and NoLowercaseQueryStringAttribute filters comes in.

Special Case 1

Say you want to have the following action method where visiting http://example.com/robots.txt returns a text result. We want the client to think it’s just visiting a static robots.txt file but in reality we are dynamically generating it (One reason for doing this is that a robots.txt file must contain an absolute URL and you want to use the UrlHelper to just handle that, no matter what domain the site is running under).

Adding a trailing slash to robots.txt would just be weird. Also, the last thing you want to do when search engines try to visit http://example.com/robots.txt is 301 permanent redirect them to http://example.com/robots.txt/. So we add the NoTrailingSlashAttribute filter.

The RedirectToCanonicalUrlAttribute knows about the NoTrailingSlashAttribute filter and when it sees it and we make a request to the above action, it ignores the AppendTrailingSlash setting and it works just like requesting a static robots.txt file from the file system.

Special Case 2

Sometimes you want your query string parameters to be a mix of upper-case and lower-case. When you want to do this, simply add the NoLowercaseQueryStringAttribute attribute to the action method like so:

If you are using the ASP.NET Identity NuGet package for authentication, then take note, you need to apply the NoLowercaseQueryStringAttribute to the AccountController.

Conclusions

Once again, you can find a working example of this and much more using the ASP.NET MVC Boilerplate project template or view the source code directly on GitHub.