Tags

, , ,

Introduction

Creating a Handler in Sitecore is not a straight forward task, so to explain this I have taken example of Managing Robots.Txt file in the Sitecore CMS content Tree.
Task:

  • We need to store and update the Robots.txt contents in the Sitecore content tree — This is a Normal process same as creating a Page in Sitecore.
  • When robots.txt is requested then read the related Sitecore node and display the content on page. — Handler is implemented for this

Robots-Content-Editor

Background 
Issue
When a txt is to be handled by asp.net, we create HTTPHandler.
To achieve the same First we created a TxtHandler and mapped it in IIS. Our TxtHandler was getting the requests for Txts. This was working fine but we were not able to access the Sitecore from Handler as the Sitecore.Context was not available in the Handler. If we don’t get the Context then we can’t access the Sitecore Tree and the Robots Txt Item.

Different Solutions
One solution was to handle it from Application_BeginRequest in Global.asax. But If we let the code run till global.asax then all Sitecore Pipelines will be executed and which can create the performance overhead as we don’t need to load Layout or anything else. We were looking for option where we can skip loading the Sitecore Pipelines and reduce performance overhead.

After some analysis and R&D we got a perfect solution

The Solution  
Create a Processor by inheriting HttpRequestProcessor from Sitecore.Pipelines.HttpRequest

Get the HttpContext in the code and get the/ Current URL. If URL ends with Robots.txt then go ahead else skip the code

If URL matches with robots.txt then get the Current DB from Context.Database and get the Robots item from the Sitecore Content Tree.

Till now the task was simple. Now here is the twist. We don’t want to process anything after this Processor is executed, functionality should be similar to Handler. We wanted to display the text from RobotsTxt item and display on the screen as Plain Text. No other pipeline should be called. We thought of some code which can skip the remaining pipeline, like setting a flag (if there is any) which can skip other pipelines. But there is no such flag or code.

But we came up with much simpler method. Response.End(). And that did the trick.

Coding part is done. Let’s go to Web.config. We need to place the Processor at a location where we can get the Sitecore Context. We tried with first line in but the context was not available. Then we started moving one line below and run. According to our understanding at least SiteResolver will load the Context and we were correct. So best placed position is right below SiteResolver.

Web.config Changes
<httpRequestBegin> 

<processor type="Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel" />

<!-- Custom Processor, The best place is after SiteResolver.   -->

<processor type="SND641.Customization.RobotsModule, SND641" /> 
Code for Processor
using System.Web; 
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Pipelines.HttpRequest;
namespace SND641.Customization
{
    public class RobotsModule : HttpRequestProcessor
    {
        public override void Process(HttpRequestArgs args)
        {
            HttpContext currentContext = HttpContext.Current;
            string sRequestedURL = currentContext.Request.Url.ToString().ToLower();
            if (sRequestedURL.EndsWith("robots.txt"))
            {
                string sOutput = "";
                Database CurrDb = Sitecore.Context.Database;
                if (CurrDb != null)
                {
                    Item RobotsItem = CurrDb.GetItem("/sitecore/content/Home/RobotsTxt");

                    if (RobotsItem != null)
                    {
                        sOutput = RobotsItem["Robots Text"];
                    }
                    else
                    {
                        sOutput = "Item is not found in " + CurrDb.Name;
                    }
                }
                currentContext.Response.ContentType = "text/plain";
                currentContext.Response.Write(sOutput);
                currentContext.Response.End();
            }
        }
    } 
}  
Points of Interest 

When I googled for the Solution for this kind of issue, I didn’t find any article which can explain me what to do when I want the Sitecore Context in the Handler. Even I tried to find Sitecore Documents. but no success.

Then in a document I found code for Processor so We thought of creating a Processor which can work as a Handler.

So far this was the only way we can have functionality of Handler in Sitecore.

Other Usage
This is useful when we have to handle some custom extensions like XML (Sitemap.xml) or ICS (outlook Calendar file).

Works with  
This Code works with Single Site Instance of Sitecore. Implementation for Multi-Site Application will be similar.

Advertisements