Sitecore comes with an awesome pipeline system, the system enables Sitecore to add all run and handle code for all sorts of stuff, the code that should be run in each pipeline, can be configured via .config files, which makes them extremely extendable for us as developers. A great example of this is the RenderField pipeline, which runs every time a field is being rendered on a page or in code via FieldRenderer(or alike Sitecore functions).
In Sitecore 7.2, the default configuration looks like this:
<renderField> <processor type="Sitecore.Pipelines.RenderField.SetParameters, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetTextFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.ExpandLinks, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetInternalLinkFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetMemoFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.GetDocxFieldValue, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel" /> <processor type="Sitecore.Pipelines.RenderField.RenderWebEditing, Sitecore.Kernel" /> </renderField>
I´ve blogged twice about extending it, in Ensuring that p-tag, and in Removing width and height from image tags
If you are making code that should be utilized or extended by others, the Pipeline system is a great way to ensure that the consumers of your code are able to extend it nicely.
In order to create your own pipelines, you need three things:
- Definition in a .config file
- A custom Argument class that inherits from PipelineArgs(this is optional)
- Atleast one Pipeline processors
1. Defining the pipeline.
This is very simple, you create a .config file in your app include, that defines the pipeline. The example I’m going to use is a pipeline that will indicate whether an item should be included in a menu. The pipeline will be called menuInclude, it is defined like this:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <menuInclude> <processor type="OxygenSoftware.Mikkelhm.BusinessLayer.Pipelines.MenuInclude.IsNavigable, OxygenSoftware.Mikkelhm.BusinessLayer" /> </menuInclude> </pipelines> </sitecore> </configuration>
That’s it for defining the pipeline.
2. Creating our own PipelineArgs
This step is optional, you could easily go with Sitecores own PipelineArgs, this class has a container you could put everything in, it’s called CustomData, and is defined in a dictionary of string, object. I like to create my own though, as it gives me type safety and direct properties to access.
The PipelineArgs looks like this:
namespace OxygenSoftware.Mikkelhm.BusinessLayer.Pipelines.MenuInclude { public class MenuIncludePipelineArgs : PipelineArgs { public bool Include { get; set; } public Item Item { get; set; } } }
This args will take the Item, we are checking, and has a bool that indicates whether the item should be included in the menu.
3. A Pipeline processor
The last thing to do is to create at least one pipeline processor that uses the args. Ill create one that that is called IsNavigable, it should check the item for some common condition that should be true, in order to be included in the menu. On our solutions, we have a concept of interface templates. There is one interface template called navigable, if another template inherits from this, it should be included in the menu.
namespace OxygenSoftware.Mikkelhm.BusinessLayer.Pipelines.MenuInclude { public class IsNavigable { public void Process(MenuIncludePipelineArgs args) { if (args.Include) { if (args.Item.IsNavigable()) args.Include = true; } } } }
This is all we need in order to start using the pipeline. We have created a PipelineManager that helps us invoke the pipeline. It looks like this:
namespace OxygenSoftware.Mikkelhm.BusinessLayer.Pipelines { public class PipelineManager { public static bool IsMenuIncluded(Item item) { var args = new MenuIncludePipelineArgs(); args.Item = item; args.Include = true; var pipeline = GetPipeline("menuInclude"); pipeline.Run(args); return args.Include; } /// <summary> /// Gets the pipeline. /// </summary> /// <param name="pipelineName">Name of the pipeline.</param> /// <returns></returns> public static CorePipeline GetPipeline(string pipelineName) { CorePipeline ppl = CorePipelineFactory.GetPipeline(pipelineName, string.Empty); if (ppl == null) { Log.Error(String.Format("Failed to load pipeline {0} from config file.", pipelineName), typeof (string)); } return ppl; } } }
This enables us to call the code, in i.e. a menu, where in order to get all children that should be included in the menu, by the following simple code:
var menuITems = Sitecore.Context.Item.Children.Where(PipelineManager.IsMenuIncluded);
This shows how you can implement Sitecores own Pipeline system, and utilize it in your code. It’s a very nice way implement functionality in your code, if it is distributed and used by others. This is true, if you are making modules for Sitecore, like we do at Oxygen Software, where our Social Intranet module relies on these features.