SEO best practices - Perform proper old site URL redirects

A common step when renewing an existing website is to take care of the old URLs. Web crawlers do not tolerate a lot of 404 response status codes that might come if users continue requesting old URLs. Instead, a good practice will be to properly redirect older URLs. In this blog post, you will learn how to do it using special third-party HTTP module named Intelligencia URL Rewriter. The module allows you to declaratively express matching rules within your application’s web.config file.

1. Install URLRewriter module

In order to use the custom URL rewriter module, you must install it's NuGet package. Once installed, the package registers the following configuration section in the web.config file:

<section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />

TIP: Use Visual Studio Package Manager Console for a better manipulation of NuGet packages. For example you can install a specific version of the URL rewriter package by using the following command: Install-Package Intelligencia.UrlRewriter -Version X.X.X

Next, HTTP modules are registered:

<add type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" name="UrlRewriter" />

By default all redirect rules are written in the web.config file. However in order to avoid loosing that info after an upgrade, you can create a special rewriter.config file in the App_Data >> UrlRewrites folder of your application. Add the following line in the web.config file just before the closing configuration tag:

<rewriter configSource="App_Data\UrlRewrites\rewriter.config">

2. Prevent redirects for Sitefinity backend

As you need to prevent URL redirects for Sitefinity backend, special custom parser class must be created. Create new class file in the UrlRewrites folder and name it SitefinityBackendExclusionConditionParser. The class must implement IRewriteConditionParser interface. It has one and only method Parse that reads the rewriter.config and if it finds an “isSitefinityBackend” section, returns an instance of SitefinityBackendExclusionCondition. Here's the full code:

/// <summary>
/// This class parses whether rewriter.config fires a condition "<if isSitefinityBackend="false">...</if>"
/// </summary>
public class SitefinityBackendExclusionConditionParser : IRewriteConditionParser
    /// <summary>
    /// Parses the specified node.
    /// </summary>
    /// <param name="node">The node.</param>
    /// <returns></returns>
    public IRewriteCondition Parse(System.Xml.XmlNode node)
        XmlNode existsAttr = node.Attributes.GetNamedItem("isSitefinityBackend");
        if ((existsAttr != null) && existsAttr.Value == "false")
            return new SitefinityBackendExclusionCondition();

        return null;

Next, another class must be created to determine whether the URL from the current HTTP request starts with “sitefinity” word. Create another class file and name it SitefinityBackendExclusionCondition:

public class SitefinityBackendExclusionCondition : IRewriteCondition
    /// <summary>
    /// Determines whether we are not on a back-end URL
    /// </summary>
    /// <param name="context">The current rewriter context.</param>
    /// <returns>True, if we are not on a back-end URL, False otherwise.</returns>
    public bool IsMatch(RewriteContext context)
        string relativePath = HttpContext
        return !relativePath.StartsWith("~/sitefinity/");

The class has a single IsMatch method that returns true if you are not on back-end URL, false otherwise.

3. Trim trailing slashes from URLs

Most of the crawlers nowadays treat URLs with and without slashes as different. Basically when there is a trailing slash, the URL is considered as a directory. Without a trailing slash, URL is treated as a file. For more information, see To slash or not to slash official Google blog post. To improve the SEO of your site, another helper class must be created. Name it TrailingSlashesTrimmerTransform. The class must implement the IRewriteTransform interface.

/// <summary>
/// This custom transformer trims slashes (and whitespace) from the end of the captured URL
/// </summary>
public class TrailingSlashesTrimmerTransform : IRewriteTransform
    /// <summary>
    /// Applies the transformation on the given input and returns the trimmed URL.
    /// </summary>
    /// <param name="input">The input url.</param>
    /// <returns>The trimmed url.</returns>
    public string ApplyTransform(string input)
        return input.TrimEnd('/', ' ');

    public string Name
        get { return "trailingSlashesTrimmerTransform"; }

The TrailingSlashesTrimmerTransform has a single property that defines the name of the section in the rewriter.config file: trailingSlashesTrimmerTransform.

Add the following lines in the rewriter.config file:

<if isSitefinityBackend="false">
<redirect method="GET" url="~/(.*)\/$" to="~/${trailingSlashesTrimmerTransform($1)}"/>

The code above uses a regular expression to find the end of the URL and replaces the end of all non-backend URLs with space where backslash (/) is found.

4. Register custom plugins

To register the custom plugins described above, add the following lines in the rewriter.config file:

       <register parser="SitefinityWebApp.UrlRewrites.SitefinityBackendExclusionConditionParser, SitefinityWebApp" />
      <register transform="SitefinityWebApp.UrlRewrites.TrailingSlashesTrimmerTransform, SitefinityWebApp" />

And finally you can start building your rewrite rules in a similar fashion as below:

5. Test URL redirects

To be able to test the URL redirects properly, you need to request an old URL from the domain of your new site and inspect whether a 301 redirect status code is returned. The page must be redirected to the newer destination.

Veronica Milcheva

About Veronica Milcheva

I am a passionate Sitefinity blogger, developer and consultant. In my spare time I enjoy running and listening to music. My personal quote: There's no tough problem, just not enough coffee :)

View Comments

comments powered by Disqus