Passing Configuration Data into a Sitecore Pipeline Processor

I’ve created an example pipeline config and an example pipeline processor to explain how to pass configuration data to your custom processor. Let’s take a look at the patch config and example processor code:

[code language=”csharp”]
using Sitecore.Collections;
using Sitecore.Diagnostics;
using Sitecore.Pipelines;
using Sitecore.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Xml;

namespace Hi.Sc.Pipelines
{
public class ExampleProcessor
{
#region Fields

private string _myArgument1 = string.Empty;
private string _myArgument2 = string.Empty;
private List<string> MyRawList = new List<string>();
private List<string> MyStringList = new List<string>();

#endregion

#region Properties

public MyObject MyObject { get; set; }
public string MyProperty { get; set; }

#endregion

#region Constructor

public ExampleProcessor()
{

}

public ExampleProcessor(string myArgument1, string myArgument2)
{
_myArgument1 = myArgument1;
_myArgument2 = myArgument2;
}

#endregion

#region Methods

public void Process(PipelineArgs args)
{
Assert.ArgumentNotNull(args, "args");
Log.Warn("ExampleProcessor.Process", this);
LogData();
}

public void AlternateProcessMethod(PipelineArgs args)
{
Assert.ArgumentNotNull(args, "args");
Log.Warn("ExampleProcessor.AlternateProcessMethod", this);
LogData();
}

public void AddString(string myStringArgument)
{
if (!string.IsNullOrEmpty(myStringArgument))
{
this.MyStringList.Add(myStringArgument);
}
}

public void AddMyRawString(XmlNode configNode)
{
Assert.ArgumentNotNull(configNode, "configNode");
string attributeValue = XmlUtil.GetAttribute("value", configNode);
MyRawList.Add(attributeValue);
}

private void LogData()
{
LogString("My Argument 1", _myArgument1);
LogString("My Argument 2", _myArgument2);
LogString("My Property", MyProperty);
LogList("My String List", MyStringList);
LogList("My Raw List", MyRawList);

if (MyObject != null)
{
Log.Warn("MyObject.Name = " + MyObject.Name, this);
}
}

private void LogList(string listName, IList list)
{
if (list != null)
{
foreach (string s in list)
{
LogString(listName, s);
}
}
else
{
LogString(listName);
}
}

private void LogString(string name, string value = "")
{
if (!string.IsNullOrEmpty(value))
{
Log.Warn(string.Format("{0} = {1}", name, value), this);
}
else
{
Log.Warn(string.Format("{0} is empty."), this);
}
}

#endregion
}

public class MyObject
{
public string Name { get; set; }
public MyObject()
{
Name = "MyObject.Name";
}
}
}
[/code]

Our patch config:

[code language=”xml”]
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<httpRequestBegin>
<processor type="Hi.Sc.Pipelines.ExampleProcessor, Hi.Sc" method="AlternateProcessMethod" runIfAborted="true">

<param desc="My Argument 1">myArgument1_Value</param>
<param>myArgument2_Value</param>

<MyProperty desc="My Property">MyProperty_Value</MyProperty>

<MyStringList hint="list:AddString">
<SomeTag1>MyStringList_String1</SomeTag1>
<SomeTag2>MyStringList_String2</SomeTag2>
<SomeTag1>MyStringList_String3</SomeTag1>
</MyStringList>

<MyRawList hint="raw:AddMyRawString">
<MyRawString value="MyRawList_MyRawString_Value1"/>
<MyRawString value="MyRawList_MyRawString_Value2"/>
</MyRawList>

<MyObject ref="MyObjectNode/MyObject"/>

</processor>
</httpRequestBegin>
</pipelines>

<MyObjectNode>
<MyObject type="Hi.Sc.Pipelines.MyObject, Hi.Sc" />
</MyObjectNode>

</sitecore>
</configuration>
[/code]

The code passes values into our processor to give you an idea on how to pass custom data into a processor. This could help give ideas on processor reuse. I’ve added this to the httpRequestBegin pipeline so I can reload my page and check my log files to see the output. I’m also calling Log.Warn instead of Log.Info since I have my log level set to WARN. Here is the output from my log file:

[code language=”text”]
8072 23:03:49 WARN ExampleProcessor.AlternateProcessMethod
8072 23:03:49 WARN My Argument 1 = myArgument1_Value
8072 23:03:49 WARN My Argument 2 = myArgument2_Value
8072 23:03:49 WARN My Property = MyProperty_Value
8072 23:03:49 WARN My String List = MyStringList_String1
8072 23:03:49 WARN My String List = MyStringList_String2
8072 23:03:49 WARN My String List = MyStringList_String3
8072 23:03:49 WARN My Raw List = MyRawList_MyRawString_Value1
8072 23:03:49 WARN My Raw List = MyRawList_MyRawString_Value2
8072 23:03:49 WARN MyObject.Name
[/code]

Setting the ExampleProcessor:
Line 5 of our patch config above initializes our processor. The type attribute tells Sitecore the namespace.class, assembly to use. In this case it is Hi.Sc.Pipelines.ExampleProcessor in the Hi.Sc.dll. The method attribute allows us to override the default Process method. Since I have set the method attribute in my processor, my example processor will call the AlternateProcessMethod instead of the default Process method. You can see the result on line 1 of the log file output. If we remove this method attribute, it will call Process instead. The runIfAported attribute set to true will run our processor even if a previous processor in our pipeline calls args.AbortPipeline() to stop processing the subsequent processors in the pipeline.

Passing Arguments to Processor Constructor:
Lines 7 and 8 of our patch config allows us to pass two arguments to the constructor of ExampleProcessor on line 36. If we remove these lines, The constructor on line 31 of ExampleProcessor will be called instead. If we only remove line 7, we will get an error when instantiating our ExampleProcessor as we do not have a constructor defined for only one argument. Please note that the desc attribute of the param tag is optional. These parameters are passed in the order that they appear and if we switch the order of lines 7 and 8, then the values will be swapped around in our log file output.

Passing Properties:
Line 10 of our patch config allows us to pass a value to Property of our processor class. When the ExampleProcessor is initalized, it will match the tag on line 10 of our patch config to the property defined on line 25 of our ExampleProcessor. We just need to make sure the tag name matches the property name.

Passing Values to a List:
Line 12 of our patch config allows us to pass values to a list in our processor. The key here is the hint attribute. By setting the hint attribute to list:[name of method we define], we can fill a list we create in our class. By calling hint=”list:AddString”, this will call the method on line 60 of our ExampleProcessor. The tag names on lines 13 through 15 do not matter, but the value inside them is what will be added to our list on line 64.

Passing Values to a List using Raw:
Line 18 of our patch config allows us to reuse the hint attribute, but instead of using list:, we will use raw:[name of method we define]. When calling hint=”raw:AddMyRawString”, this will call the method on line 68 of our ExampleProcessor. Notice that when we use raw, a System.Xml.XmlNode will be passed in as opposed to the AddString method which has a string argument. When we have an XmlNode, we are able to use Sitecore.Xml.XmlUtil.GetAttribute to extract the value attribute as seen on line 71. We then add that to the MyRawList in this example.

Passing an Object using Ref:
Line 23 is an interesting one in our patch config. We can see that is setting a Property on line 24 of our ExampleProcessor class, since the tag has the same name as the property in our class. Here we can see that type is not a string, MyObject is defined on line 119 of our code. By using ref attribute, this points to another location in out patch config, here it is pointing to line 30 in our patch config where we have set the type attribute to know what type of object to return to our Property. Alternatively, we could just add a type attribute instead of a ref attribute and set the class and assembly to pass that to MyObject.