Adapting the 301 Redirect Module to Sitecore 7

September 2, 2014

Blog | Development | Adapting the 301 Redirect Module to Sitecore 7
Adapting the 301 Redirect Module to Sitecore 7

On a recent Sitecore 7 project, we were faced with handling a significant number of 301 redirects.  When I’m usually faced with this problem, I’ve relied on the tried and tested method of adding the URL Rewrite Module to IIS and configuring the redirects in the web.config for the application.  This time, I went looking for a Sitecore alternative.  Lo and behold, I discovered the 301 Redirect Module in the Sitecore Marketplace.  At first glance, this appeared to be the solution I was looking for – a content managed approach to 301 redirects. 

Unfortunately this module is only listed as being tested in Sitecore 6.5 and older.  To ensure its success in Sitecore 7, I would need to perform some testing and possible modifications. To start, I grabbed the raw source out at GitHub.  As we already had an existing solution, I brought in each piece of code from GitHub and changed namespaces/usings as needed.  I inspected the code, namely the Redirects.cs class which performs the actual redirects.  Nothing appeared to lean on any Sitecore 6 libraries too heavily, so I decided to build and test it out.  My initial testing showed that the redirects were working properly in my Sitecore 7 instance.  The initial tests involved performing redirects from within one site, e.g. http://mysite.com/old-page -> http://mysite.com/new-page.  Next, due to requirements of the project, I began testing with multiple websites and multiple languages.  That’s when I started having problems.

The initial request was being altered by the time my processor was exposed.  For example, if I hit the webpage with http://mysite.com/en/old-page, by the time the request was received by the processor, the /en portion of the URL was removed.  This occurs because Sitecore’s language processor attempts to resolve the language based on the URL.  The old site used the /en prefix as well, which was the culprit.  I was now faced with a dilemma- the 301 Redirect processor had to fire after the ItemResolver processor, but at this point the request was altered.  My next task would be to create another processor that would fire prior to Sitecore altering the request due to the language prefix.  This new processor would need to grab the initial request and then pass it to the existing processor.

 

Passing a Value From One Pipeline To Another

 




I created another processor and set it to fire as the first item in the preprocessRequest pipeline.  This processor was extremely simple:


public class OriginalRequest : PreprocessRequestProcessor
    {
        public override void Process(PreprocessRequestArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            Context.Items.Add("original request", args.Context.Request.Url.ToString().ToLower());
        }
    }


This processor simply grabs the Request URL and adds it to the Context.Items dictionary.  This dictionary is the key to passing values between multiple processors.  This dictionary is exposed from the Sitecore.Caching namespace to allow developers to add/remove as they deem appropriate.



With our original request now captured, the remaining work involves altering the Redirect.cs code to read our request value instead of the value at the time the processor fires.


public override void Process(HttpRequestArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            if ((Context.Item != null || args.LocalPath == "/layouts/system/visitoridentification") || (Context.Database == null)) return;
 
            var request = Context.Items["original request"];
 
            if (request == null) return;

Only the pertinent code is shown for brevity.  The change takes place in the Process method of the processor, prior to the redirect items being read. 

We can now confidently state that any request formats can be handled by our redirects.  This method was tested with multiple languages with a Sitecore instance with multiple sites.  The config changes can be seen below:


<pipelines>
<preprocessrequest>
<processor patch:before="processor[@type='Sitecore.Pipelines.PreprocessRequest.SuppressFormValidation, Sitecore.Kernel']" type="Framework.Sitecore.SharedSource.Redirects.OriginalRequest,Framework">
</processor></preprocessrequest>
<httprequestbegin>
<processor patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" type="Framework.Sitecore.SharedSource.Redirects.Redirects,Framework">
</processor></httprequestbegin>
</pipelines>

John Rappel

Technical Lead
Tags
  • Sitecore
  • Tutorial

Recent Work

Check out what else we've been working on