Case-sensitive SEO URL redirects and routing for IIS and ASP.NET MVC

At NeoSmart Technologies, we have a special affinity for ecosystems running both Windows and *nix in unison, each doing things they excel at. Half of this website is running ASP.NET MVC under IIS 8.0, while the other half is running under nginx on FreeBSD, everything behind an nginx reverse proxy. Windows likes to make things easy for users by being a primarily case-insensitive platform, both when it comes to the local filesystem and the web. FreeBSD and Linux on the other hand, like most of the unix world1 are explicitly and unapologetically case-sensitive.

On the one-hand, IIS defaulting to case-insensitive URL routing means that your users are far less likely to a see a 404 “Page not found” error as a result of a fat-fingered or mangled URL (which as we all know can be the fault of either the user or the developer), but it also means that when Google’s spiders and ‘bots come around looking to index your content, you’re likely to wind up penalized for having duplicate content. The web itself is officially case-insensitive, and technically both and are completely separate, unique, and independent URLs that despite all semantical similarities share nothing in common (though you’d be mad to actually host different content on URLs differing only in spelling).

Welcome SeoRedirect, part of NeoSmart Technologies’ open-sourced Web Toolkit library, which provides case-sensitive routing for ASP.NET on IIS. With the latest update (freshly pushed!), SeoRedirect also gives you control over which GET parameters are also preserved, because apparently worrying about case-sensitivity alone just isn’t enough.

The redirection will point to the URL using the same case as the controller class name and the action method name in your code file. e.g. For a action method HomeController.SamplePage, requests to anything other than /Home/SamplePage with that same case will be redirected to /Home/SamplePage, including requests for /home/samplepage, /home/samPLEpAge, etc. It also detects and handles (in an opinionated fashion) cases for the Index() method of a controller, and offers the option of explicitly specifying which GET parameters form a part of the pages identity and which are superfluous and should be stripped for incoming requests.

Usage is quite simple: just copy-and-paste the following line to the start of every method you desire to be SEO-redirected:


If you add using NeoSmart.Web; to your imports, that can be shortened to


And if you prefer to invoke it as an extension method instead, it can be as short as


In addition to normalizing case, SeoRedirect will also strip/remove superfluous /Index/ references, remove trailing backslashes from requests to the “directory” page (method without parameters) and add trailing backslashes to non-directory requests (methods with parameters).

Example: for a given directory, index action SoftwareController.Index(), SeoRedirect will convert any of the following links to the correct URI

  • etc.

Example: for a given action SoftwareController.Something(id), SeoRedirect will convert any of the following links to the correct URI (whatever parameter might be):

  • etc.

Just as the case forms an integral part-and-parcel of the identity of the requested URL, so do GET parameters, which are tagged on following a ? in the request URL. As your appointed URL helper and trusted friend, SeoRedirect will actually automatically retrieve a list of parameters that you expect to be passed along from the method declaration in your MVC controller and will preserve these in all cases, but it also lets you specify which additional GET parameters (if any) to keep.


public class OrderController : BaseController
public ActionResult View(int id, int downloadId = 1)
this.SeoRedirect(new [] { "utm_nooveride" });

When used as shown in the example controller above, SeoRedirect will automatically determine that the action portion of the URL must match the case of “Place” and the controller portion of the URL should be spelled out “Order” (and not “order” or “ORDER” or anything else). In addition, it’ll automatically determine that id in this specific usage based off of the default MVC routing rules (which it’ll check for) comprises a part of the URL and not a GET parameter, that downloadId could be a GET parameter if it’s present (but that it could be elided or submitted as a POST value), and that you also explicitly want to preserve the GET parameter “utm_nooverride”, should it be found.

In this case, rewrites would redirect as follows:

/Order/7          => /Order/7 (no redirect)
/Order/7/?downloadId=13 => /Order/7?downloadId=13
/ORdeR/7/?utm_nooverride=1&downloadId=13&test => /Order/7?utm_nooverride&downloadId=13
/order/7?id=13 => /Order/7

There are even options available to strip or keep all query strings while processing other redirect rules normally:

Seo.SeoRedirect(this, Seo.QueryStringBehavior.KeepAll);
Seo.SeoRedirect(this, Seo.QueryStringBehavior.StripAll);
Seo.SeoRedirect(this, Seo.QueryStringBehavior.KeepActionParameters); //default

Bottom line: if you care about your search ranking, want to boost your SEO, wish to preserve the cleanliness of your URLs, want a better site experience for your visitors and customers, and want to do your bit helping make the world a better place – start using SeoRedirect.

(btw, we’ve taken into account the fact that you will be trusting us to handle each and every (uncached) request made to your site, and we’ve gone above and beyond to make SeoRedirect as reliable as possible without sacrificing its speed. You can look at the code for yourself and see how we’ve done it – we’ve worked hard to achieve the right mix of magic, performance, and reliability).

  1. Mac OS X is a notable exception here, as by default it uses HFS+ in a case-insensitive mode, though an HFS+ implementation w/ case-sensitivity is enabled (but rarely used). 

Leave a Reply

Your email address will not be published. Required fields are marked *