Saturday, 31 May 2014

Notes on Lowercase Sitecore URL's

Most customers that I work with consider the provision of standardised lowercase URL's to be a basic requirement for their site. In this post, I discuss some issues that Sitecore developers face in trying to meet that requirement. I also provide some simple code snippets that you might find helpful.




Generating Lowercase URL's

Sitecore 6.6 introduced a lowercaseUrls property to the link provider which, if set to "true", ensures that every link it generates is lowercase. If you're still working with an earlier version of Sitecore then achieving this result is a bit more work, but still pretty easy using the following code:
public class LowercaseLinkProvider : LinkProvider 
{
    // Whenever you get asked for a URL then simply use the base
    // functionality and convert returned the string to lowercase.
    public override string GetItemUrl(Item item, UrlOptions options)
    {
        return base.GetItemUrl(item, options).ToLower();
    }
}
Just replace the default link provider class in the web.config with the one above. Better still, use Sitecore's include file patching facilities:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <linkManager>
      <patch:attribute name="defaultProvider">lowercase</patch:attribute>
      <providers>
        <add name="lowercase" type="MySite.LowercaseUrlCheck, MySite" />
      </providers>
    </linkManager>
  </sitecore>
</configuration>
So that's all fine an dandy. We have Sitecore providing lowercase URL's and we can all congratulate ourselves on a job well done. Well maybe, but in my experience this usually isn't the whole story. When customers ask for the lowercase links they're normally seeking to meet a specific SEO requirement. They want to ensure that there is only one acceptable version of a URL. We haven't achieved that yet.

Receiving Non-Lowercase Requests

As with many aspects of Sitecore, if you alter the way links are provided you should also give some consideration to the way they're resolved. While Sitecore is producing only lowercase links, it's still more than happy to accept requests with any combination of upper and lower case characters in the URL. Anybody who manually types the address or clicks a link from an external source might bypass your efforts.

So what do we do? There are two options. If you're a strict hard-liner, you could 404 all requests that contain any uppercase characters, but a more measured approach would be to redirect all non-lowercase requests to their lowercase equivalents. Here's a simple processor that you can add to the httpRequestBegin pipeline to achieve that goal.
class LowercaseUrlCheck
{
    public override void Process(HttpRequestArgs args)
    {
        // if there is no context item, then 
        // there's no need to redirect.
        if (Sitecore.Context.Item == null)
            return;

        String requestUrl = HttpContext.Current.Request.RawUrl;
        String loweredUrl = requestUrl.ToLower();

        // if the requested URL is entierly lowercase
        // then there's no need to redirect.
        if (requestUrl == loweredUrl)
            return;

        HttpContext.Current.Response.Redirect(loweredUrl);
    }
}
Here's the config patch. Notice that we're adding the new processor after Sitecore's ItemResolver processor. if the item hasn't already been resolved, then we won't bother redirecting.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor type="MySite.LowercaseUrlCheck, MySite" patch:after=
        "*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, 
        Sitecore.Kernel']"/>
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>
You might be concerned that all this redirecting will negatively impact the performance of the site. But remember we're producing exclusively lowercase links internally. A redirect should only occur when an external source links to your sight with a URL containing uppercase characters..

You can of course achieve lowercase redirects in IIS before the request reaches Sitecore, but this is a simple in-code alternative. It also that means you can add any required embellishments to the code using information that might only be available from Sitecore context.

If you don't want to implement this functionality yourself there are some modules that can do it for you (take a look in the links below), but I find that requirements differ enough from project to project that a bespoke solution is often a good idea.

Here's some other articles that may be of interest: