Wednesday 24 February 2016

Pipelines - Sitecore development basics

Pipelines are very important mechanism in Sitecore. They organize processed tasks in a very clear, classified and highly customizable way.

Pipelines contain processors, which execute specified actions, one after one. Each processor can abort whole pipeline, so subsequent processors won't be executed.

Processor must contain Process() method that returns void and accepts single argument based on class Sitecore.Pipelines.PipelineArgs or its derivative.

public class CustomPipelineProcessor
{
    public void Process(Sitecore.Pipelines.PipelineArgs args)
    {
        // Your logic
    }
}

To make your processor work, you need to bind it to pipeline in configuration file. Let's look at the <httpRequestBegin> pipeline configuration (Sitecore 8.1):

<httpRequestBegin>
  <processor type="Sitecore.Pipelines.PreprocessRequest.CheckIgnoreFlag, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.EnsureServerUrl, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.StartMeasurements, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.IgnoreList, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.UserResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.DatabaseResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.BeginDiagnostics, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.DeviceResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.LanguageResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.CustomHandlers, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.FilterUrlExtensions, Sitecore.Kernel">
    <param desc="Allowed extensions (comma separated)">aspx</param>
    <param desc="Blocked extensions (comma separated)">*</param>
    <param desc="Blocked extensions that stream files (comma separated)">css,js</param>
    <param desc="Blocked extensions that do not stream files (comma separated)">*</param>
  </processor>
  <processor type="Sitecore.Pipelines.HttpRequest.QueryStringResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.DynamicLinkResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.DefaultResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.FileResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.DeviceSimulatorResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel" />
</httpRequestBegin>

As you can see, there are a list of processors in pipeline. Names are meaningful, there are processors which resolve current site, user, database, etc.

So when we want to put our processor to pipeline, we create configuration patch file:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor type="SitecoreExperiments.Common.Pipelines.CustomPipelineProcessor, SitecoreExperiments.Common" 
                   patch:after="*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

In this example patch code, new processor is added to httpRequestBegin pipeline. It is added just after ItemResolver processor, beacuse I set it by this attribute:

patch:after="*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']"
Setting this is not necessary, I just wanted to show that it can be achieved.

I made sure that my config patch is loaded last, so I named it SitecoreExperiments.Common.Pipelines.config and I put it in directory named Z_SitecoreExperiments in \Website\App_Config\Include. After checking configuration at /sitecore/admin/showconfig.aspx I am sure that my patch works as expected:


Object that is passed to function can be modified by each processor, so subsequent processors can rely on data that is added or resolved previously. We can create our own class that inherits from Sitecore.Pipelines.PipelineArgs and adds custom fields or, for example, use CustomData SafeDictionary property:

public void Process(Sitecore.Pipelines.PipelineArgs args)
{
    args.CustomData.Add("CustomPipelineProcessor""Hello, is it pipeline I've been looking for?");
}

Pipelines can be run from code using method CorePipeline.Run()

var args = new Sitecore.Pipelines.PipelineArgs();
Sitecore.Pipelines.CorePipeline.Run("customPipeline", args);
 
// - result will be "Hello, is it pipeline I've been looking for?"
String result = args.CustomData["CustomPipelineProcessor"].ToString();

Pipeline Profiler

There is also useful tool to diagnose pipelines that run in our solution. It is disabled by default, to enable it rename configuration include file Sitecore.PipelineProfiling.config.disabled to Sitecore.PipelineProfiling.config. This config has two settings:

<setting name="Pipelines.Profiling.Enabled" set:value="true" />
This enables whole profiling.

<setting name="Pipelines.Profiling.MeasureCpuTime" set:value="true" />
This enables CPU time measurement. By default this is disabled.

 It can be accessed by url /sitecore/admin/pipelines.aspx. 




Share it:

Radosław Kozłowski - Senior Sitecore Developer Radoslaw Kozlowski

Author & Editor

Sitecore MVP, passionate Sitecore & .NET developer and architect. Sitecore Community evangelist.

1 comments:

  1. Thanks Nasreen, I appreciate your opinion. I'm glad that my posts are helpful :)

    ReplyDelete