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 duplicat
Based on the answer from Gabe Sumner, but without redirects for JS, images and other content. Works only on controller actions. The idea is to do the redirect later in the pipeline when we already know its a route. For this we can use an ActionFilter.
public class RedirectFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var url = filterContext.HttpContext.Request.Url;
var urlWithoutQuery = url.GetLeftPart(UriPartial.Path);
if (Regex.IsMatch(urlWithoutQuery, @"[A-Z]"))
{
string lowercaseURL = urlWithoutQuery.ToString().ToLower() + url.Query;
filterContext.Result = new RedirectResult(lowercaseURL, permanent: true);
}
base.OnActionExecuting(filterContext);
}
}
Note that the filter above does not redirect or change the casing for the query string.
Then bind the ActionFilter globally to all actions by adding it to the GlobalFilterCollection.
filters.Add(new RedirectFilterAttribute());
It is a good idea to still set the LowercaseUrls property to true on the RouteCollection.