Luke Smith

Write today, wrong tomorrow

Generating and enforcing that any link and request is lowercase with ASP.NET MVC

This post is based off 2 other blog posts I found which helped me come up with my solution with some slight modifications on their code.

For my new project I’m having my URLs all lowercase, as some search engines interpret ‘/Home’ and ‘/home’ as two different locations. So the problem became “how can I enforce all my URLs get rendered as lowercase, and how do I force a request to a URL with an uppercase letter to redirect to the lowercase equivalent?”.

Because I’m using ASP.NET MVC I needed a way to get the Routing engine to render the URL as lowercase when using an ActionLink. Asking the question over on stackoverflow I got a solution that involved creating my own class that inherits from Route, which I’ve called LowercaseRoute, and overrides the GetVirtualPath method. I also created a MapLowercaseRoute extension method on the RouteCollection class that allows me to map a LowercaseRoute easily.

public class LowercaseRoute : Route
{
public LowercaseRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}

public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}

public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var virtualPath = base.GetVirtualPath(requestContext, values);

if (virtualPath != null)
{
virtualPath.VirtualPath = virtualPath.VirtualPath.ToLowerInvariant();
}

return virtualPath;
}
}

Next up is to ensure that any request to the site is enforced to be lowercased, and perform a 301 redirect if not. For this I’ve created a HttpModule, EnforceLowecaseRequestHttpModule, which I then register in the web.config. I could have put this directly into the global.asax file but I wanted to make it easily reusable on future projects.

public class EnforceLowercaseRequestHttpModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}

private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;

// If upper case letters are found in the URL, redirect to lower case URL (keep querystring the same).
string requestedUrl = ((application.Context.Request.Url.Scheme + "://" + application.Context.Request.Url.Authority + application.Context.Request.Url.AbsolutePath));

if (Regex.IsMatch(requestedUrl, @"[A-Z]") == true)
{
string lowercaseUrl = requestedUrl.ToLower();
lowercaseUrl += HttpContext.Current.Request.Url.Query;

application.Context.Response.Clear();
application.Context.Response.Status = "301 Moved Permanently";
application.Context.Response.AddHeader("Location", lowercaseUrl);
application.Context.Response.End();
}
}
}
Advertisement

2 Responses to Generating and enforcing that any link and request is lowercase with ASP.NET MVC

  1. Mike Henry March 29, 2010 at 9:16 pm

    Thanks for the great example!Is there any particular reason you are using HttpContext.Current when appending the query string as opposed to application.Context you use everywhere else?

  2. lukesmith March 30, 2010 at 6:42 pm

    @MikeHenry No reason why I’m using HttpContext.Current, I hadn’t spotted I was using it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.