Custom Pipeline Component in C#:
Introduction
This tutorial will show how to create a custom pipeline component for Biztalk server 2010. The pipeline component will be called “PeopleReader”. The pipeline task is simple; it is going to consume an xml file on the receive port from a specified location, and then write a modified file to another location.
The xml content before passing through BizTalk:
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<People>
<FirstName>Peter</FirstName>
<LastName>Decosta</LastName>
</People>
The final xml file after passing through Biztalk :
<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<People>
<FirstName>your_First_Name</FirstName>
<LastName>your_Last_Name</LastName>
</People>
The tutorial is going to cover all aspects of the custom pipeline coding, adding to orchestration, setting up ports, and debugging.
- Creating C# project:
Open VS 2010 as administrator then go to “New Project“, then under Visual C# select Windows then class library, and name it People Reader (fig.1).

Fig. 1 creating the PeopleReader Class for the Custom Pipeline component
1.2 Adding references
The first step after the project is created is to add a reference to the BizTalk pipeline. In order to accomplish that, go to solution explorer; right click “references “then select “Add”. On the Add Reference Dialog box select the “Browse” tab then go to your Biztalk server 2010 installation directory, in the case of this tutorial it’s “C:\Program Files (x86)\Microsoft BizTalk Server 2010″ then select the reference “Microsoft.BizTalk.Pipeline.dll” then hit the “OK” button (fig2). Then right Click on “Class1.cs” then “rename”. Call the file “PeopleReader.cs”. Next Step is to add the namespaces necessary for this project and these are the following:
using System;
using System.Xml;
using System.IO;
using System.Collections;
using System.Text;
//Biztalk stuff
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
Fig.2 Adding a reference to “Microsoft.BizTalk.Pipeline.dll”.
In order to build a custom Pipeline class, our Peoplereader class need to inherit from four interfaces which are in no specific order: IComponent, IcomponentUI,IpersistPropertyBag and IbaseComponent.
Public
class
PeopleReader: IbaseComponent
,IcomponentUI
,IpersistPropertyBag
,IcomponentUI
{
}
Since this is a small project all the code can be in one file, however, in case the pipeline required heavy coding, I would recommend declaring the people reader class as partial, then separating the code to different files each inheriting from a different Interface, that will greatly facilitate readability, and scalability since multiple developer could be working on different parts of the Custom Pipeline.
Our next step is to declare that this class is going to a Pipeline component we do that by adding the following:[ComponentCategory(CategoryTypes.CATID_PipelineComponent)] above the class declaration. Then we define where in the pipeline this component will go, by adding [ComponentCategory(CategoryTypes.CATID_Decoder)] which means that the component can only be added in the decoder stage of a receive pipeline. Last we need to create a “GUID” since it’s required for use in COM interop. To generate a new “GUID” go to the Tools Menu, then select the “Create GUID” Option, select GUID format 6 then hit copy (fig. 3). Paste the new GUID in [System.Runtime.InteropServices.Guid("0D212B7D-F3E9-418B-92BA-9FBC36CF2948")] right above the class declaration.

Fig.3 Creating a new GUID
-
Defining public properties
After adding the GUID, we declare two private member strings (m_FirstName, m_LastName) along with their (get, set) properties. Those properties will allow the user to modify the content of <FirstName> and <LastName> Tags by exposing the properties to the pipeline designer at design time.
Your code should look like this at this point
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Decoder)]
[System.Runtime.InteropServices.Guid("0D212B7D-F3E9-418B-92BA-9FBC36CF2948")]
public
partial
class
PeopleReader: IBaseComponent
,IcomponentUI
,IpersistPropertyBag
,IcomponentUI
{
private
string m_FirstName;
private
string m_LastName;
public
string FirstName
{
get
{
return m_FirstName;
}
set
{
m_FirstName = value;
}
}
public
string LastName
{
get
{
return m_LastName;
}
set
{
m_LastName = value;
}
}
}
1.4 Defining the IBaseComponent Members
Next we will define the IBaseComponent members. For ease of readability we create a new region then define the properties Description, Name, and version which represent the description for the Pipeline component we are creating, the Name as it will be seen in the BizTalk project and the version number.
#region IBaseComponent members
public
string Description
{
get
{
return
“Pipeline component to Read XML with Peoples Name”;
}
}
public
string Name
{
get
{
return
“PeopleReader Test Pipeline”;
}
}
public
string Version
{
get
{
return
“1.0.0.0″;
}
}
#endregion
- Defining the IComponentUI Members
Next up is the IcomponentUI interface members, which contains the icon that will show up in Biztalk toolbox for pipeline and a validate method. We are going to define the icon to be the default system icon, and as far as validation we are not going to add any validation at this stage.
#region IcomponentUI members
public
IntPtr Icon
{
get
{
return
new System.IntPtr();
}
}
public
Ienumerator Validate(object projectSystem)
{
return
null;
}
#endregion
}
1.6 Defining the IPersistPropertyBag Members
IPersistPropertyBag Has 4 methods: GetClassID, InitNew, Load and Save
GetClassID: return a unique ID (the GUID we defined earlier) that represents the component
InitNew: used to establish structures (data, caching..) used by other IPersistPropertyBag methods, we are going to leave it blank for this tutorial
Load: used to load the properties values (in this case the value the user enters at design time)
Save: same as load but used to save the values.
In the code below I used two helper functions ReadPropertyBag and WritePropertyBag that are called from within the Load and Save methods.
#region IPersistPropertyBag members
public
void GetClassID(out
Guid classID)
{
classID = new
Guid(“0D212B7D-F3E9-418B-92BA-9FBC36CF2948″);
}
public
void InitNew()
{
}
public
void Load(IPropertyBag propertyBag, Int32 errorLog)
{
string val = (string)ReadPropertyBag(propertyBag, “FirstName”);
if (val != null)
m_FirstName = val;
else
m_FirstName = “N/A”;
val = (string)ReadPropertyBag(propertyBag, “LastName”);
if (val != null)
m_LastName = val;
else
m_LastName = “N/A”;
}
public
void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
object val = (object)m_FirstName;
WritePropertyBag(propertyBag,“FirstName”,val);
val=(object)m_LastName;
WritePropertyBag(propertyBag,“LastName”,val);
}
private
static
object ReadPropertyBag(IPropertyBag propertyBag, string propertyName)
{
object val = null;
try
{
propertyBag.Read(propertyName, out val, 0);
}
catch (ArgumentException)
{
return val;
}
catch (Exception ex)
{
throw
new
ApplicationException(“Error reading propertybag: “ + ex.Message);
}
return val;
}
private
static
void WritePropertyBag(IPropertyBag propertyBag, string propertyName, object val)
{
try
{
propertyBag.Write(propertyName, ref val);
}
catch (Exception ex)
{
throw
new
ApplicationException(“Error Writing propertybag: “ + ex.Message);
}
}
#endregion
1.7 Defining IComponent Members
Finally the most important Interface of the custom pipeline Icomponent which has one method Execute. BizTalk calls the execute method to process the message, and then passes the context of the message and the message.
#region Icomponent members
public
IbaseMessage Execute(IpipelineContext pContext, IbaseMessage pInMsg)
{
IbaseMessagePart bodyPart = pInMsg.BodyPart;
StringBuilder outputMessageText = null;
if (bodyPart != null)
{
Stream originalStream = bodyPart.GetOriginalDataStream();
if (originalStream != null)
{
XmlDocument xdoc = new
XmlDocument();
xdoc.Load(originalStream);
XmlElement root = xdoc.DocumentElement;
XmlNodeList firstName = xdoc.GetElementsByTagName(“FirstName”);
XmlNodeList lastName = xdoc.GetElementsByTagName(“LastName”);
outputMessageText = new
StringBuilder();
outputMessageText.Append(“<?xml version=\”1.0\”
encoding=\”ISO-8859-1\”?>”);
outputMessageText.Append(“<” + root.Name + “>”);
outputMessageText.Append(“<” + firstName[0].Name + “>”
+ this.m_FirstName + “</” + firstName[0].Name + “>”);
outputMessageText.Append(“<” + lastName[0].Name + “>”
+ this.m_LastName + “</” + lastName[0].Name + “>”);
outputMessageText.Append(“</” + root.Name + “>”);
byte[] outBytes =
System.Text.Encoding.ASCII.GetBytes(outputMessageText.ToString());
MemoryStream memStream = new
MemoryStream();
memStream.Write(outBytes, 0, outBytes.Length);
memStream.Position = 0;
bodyPart.Data = memStream;
pContext.ResourceTracker.AddResource(memStream);
}
}
return pInMsg;
}
#endregion
1.8 Compilation and strong key creation for Assembly
Finally we can compile the code and check that the solution build succeeded. Next step though is to assign a key to the assembly.
Start the “Visual Studio” command prompt (fig 1.4). Make sure it’s not the windows command prompt!!!

Fig.1.4 starting the VS command Prompt
Go to the directory where your solution is, to do that type CD\ + whatever_your_directory_is in our case it’s CD\ Users\yourusername\Documents\Visual Studio 2010\Projects then hit enter. For the simplicity I am going to create a key under C:\temp (fig. 5)

Fig. 5 creating a strong key
After the key is created go to solution explorer, then right click on your project and select properties. Select the signing tab then check the “sign assembly” check box, and from the drop down menu select browse, then navigate to where you create your strong key (fig. 6).

Fig. 6 attaching the strong key to the assembly
Then compile again!