In this article, we'll see how to create and use a custom pipeline component in BizTalk Server 2004. Our component will receive a ZIP file, uncompress it, and send its contents to BizTalk Server. Although the article seems complicated, you'll see that create a custom pipeline component is quite a simple task. Our project will use a free Zip library, the ICSharpZipLib. This library can be found at the IC#Code web site.
Creating a Custom Pipeline
A Custom Pipeline component is nothing more than a simple .NET DLL that implements a class with some predefined interfaces. This interface represents the layer between a .NET Program and then BizTalk Server. We'll start creating a new C# Class Library project called UnzipDisassembler.
Now that we created the project, we need to add our references. The first reference we'll need is that to the ZIP Library. After downloading the latest version of it, add a reference to our project.
After adding the reference to the Zip Library, we'll need a reference to a BizTalk Server library. This library can be found at the BizTalk Server install folder (\Program Files\Biztalk Server 2004, to be more precise). The name of this library is Microsoft.Biztalk.Pipeline.dll, it contains the basic interfaces we'll need to process the Zip file message.
Coding the class
Now, we'll start coding our custom pipeline component. We'll start creating the
using clauses necessary for the implementation of the pipeline. The list of the
using statements is:
Now, we'll update the name of the class in the project. Change the default
Class1 name to
UnzipDisassemblerComponent (you can change the name of the physical file as well). The class should have a similar structure as shown below:
public class UnzipDisassemblerComponent
Implementing the Interfaces
To create a custom pipeline component, we need to implement some default interfaces. If we want to create a generic pipeline component, we need to implement
IPersistPropBag interfaces. Since we're working with the disassembler component, we'll not use the
IComponent interface, we'll replace it for
IDisassemblerComponent. Besides using these interfaces, we need to add some attributes to our class. These attributes are the "Component Category Attributes", that indicate that our class is a custom pipeline component, and the
System.Runtime.InteropServices.Guid, that we'll use to generate a unique identifier for our custom pipeline component. You can obtain a new GUID to your component using Visual Studio: in the Tools menu, use the Create GUID option. The implementation of the class should be similar to the code shown below:
public class UnzipDisassemblerComponent : IBaseComponent,
Now that we've added the interfaces to the class, we need to implement them. We'll start with the
The fist interface we'll implement is the
IBaseComponent. This interface has three properties that we must implement. To implement these properties, we'll use the Class Viewer. If the class viewer is not visible, go to the View menu and select Class Viewer. In the Class Viewer, expand our newly created class (
UnzipDisassemblerComponent), expand Bases and Interfaces, and you'll see the four interfaces we have implemented. Expand the
IBaseComponent, and you'll see the Class Viewer as shown below:
Right click the
Description property and select the Add>Override option. A new function will be created in your class. Repeat the process for the other two properties.
Each one of this properties returns some information about your custom pipeline component. The
Name property returns the name of the component. The
Description property returns a brief description of what you component does. The
Version property returns the current version of the component. The code below has the implementation of these three properties:
public string Description
return "Componente de descompactação para Biztalk";
public string Name
public string Version
This interface defines the behavior of the component in the BizTalk pipeline designed. We'll need to implement a method and a property. The
Validate method is used to validate the properties that are set in the custom pipeline component, and it's called when a pipeline that uses the pipeline component is compiled. Since we're not implementing any properties here, we'll use the default behavior of this method. The
Icon property represents the icon associated with the component (shown in the toolbox). In this case, we'll use the default icon, so let's leave the code as is. The complete implementation of this interface is shown below:
public System.Collections.IEnumerator Validate(object projectSystem)
public System.IntPtr Icon
return new System.IntPtr ();
IPersistPropertyBag interface is used to store the properties that are set in the pipeline component in the pipeline designed. We use the
Save methods. In our component, we're not using properties, so we don't need any implementation here. We just have to implement this interfaces because they are mandatory.
public void GetClassID(out Guid classID)
classID = classID = new Guid("6118B8F0" +
public void InitNew()
public void Load(IPropertyBag propertyBag, int errorLog)
public void Save(IPropertyBag propertyBag,
bool clearDirty, bool saveAllProperties)
Note that the
GetClassID property should return the same GUID used in the class attributes of the component.
This interface is the most important of our component. The
Disassemble method is responsible for the process of mounting the messages to BizTalk. With this component, we can receive a message as an input and generate many messages as output. As an example, we can have a single .ZIP file with multiple XML files in it. We need to consider each XML file as a single message. To do this, our disassemble component must create a list of output messages. The
GetNextMessage is called just after the disassemble method. This method is responsible for returning the messages to BizTalk, and it executes as long as the method returns a message. When the method returns
null, it considers that there are no more messages to be retrieved from the original assembled message. Implement the two methods of this interface using the class wizard. The code should be like the one shown below:
public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
public IBaseMessage GetNext(IPipelineContext pContext)
Implementing the Unzip Logic
The unzip logic will be implemented inside the
Disassemble method. This method receives as an input parameter a context and a message. The context parameter represents the execution context of BizTalk Server, and the message parameter represents the zipped message itself. The message is represented by an interface called
IBaseMessage. This interface has information about the message (context) as well as the body of the message, that can be obtained from the
Body property. The body of the message (as well as any other "part" of the message) is represented by the
IBaseMessagePart interface. This interface has some methods that allows us to read the message as an input stream. The code below obtains the body of the received message as a stream (this code should be implemented in the
msgPart = pInMsg.BodyPart;
strmZipFile = msgPart.GetOriginalDataStream();
ZipInputStream oZipStream = new ZipInputStream(strmZipFile);
Note that we're creating a
ZipInputStream from the original stream. This kind of a stream is available in the Zip library, and we'll use it to uncompress the message. Since our file can have more than one uncompressed files in it, we'll store the uncompressed files generated in a
Queue object. To do this, we'll implement a new instance of the
Queue class in our class.
System.Collections.Queue qOutputMsgs = new System.Collections.Queue();
Now, let's go back to the
Disassemble method. The
ZipInputStream class has a method called
GetNextEntry that returns an entry to an uncompressed file inside the Zip file. Each entry represents a single file in the original Zip file. Using the code below, we'll extract this entry from the Zip file and create a new output message to BizTalk, adding it to our
ZipEntry sEntry = oZipStream.GetNextEntry();
while(sEntry != null)
MemoryStream strmMem = new MemoryStream();
byte aBytes = new byte;
int inOffSet = 0;
int outOffSet = 0;
int iRead = oZipStream.Read(aBytes, 0, 2048);
while(iRead != 0)
strmMem.Write(aBytes, outOffSet, iRead);
outOffSet += iRead;
iRead = oZipStream.Read(aBytes, inOffSet, 2048);
inOffSet += iRead;
msgPart.Data = strmMem;
outMsg = pContext.GetMessageFactory().CreateMessage();
outMsg.BodyPart.Data = strmMem;
sEntry = oZipStream.GetNextEntry();
Note that to create an output message to BizTalk, we're using the context object that we received as a parameter. This context accesses BizTalk's
MessageFactory, that allows us to create messages to BizTalk.
Returning the messages to BizTalk
Now, we need to implement the
GetNextMessage method. This method is called for each message we'll return to BizTalk. When there are no more messages, the method will return
null. Since our output messages are available in our
Queue, we'll use the
Dequeue method to return them. When the
Queue is empty, we'll return
null to finish the pipeline component process. The code below implements this functionality:
Compiling the project
Before we compile our project, we should change some of the properties of the project. The first project we need to change is the output path of the assembly. In order to work with BizTalk, custom pipeline components should be placed in a specific BizTalk folder (the \Program Files\Microsoft BizTalk Server 2004\Pipeline Components). The properties of the project should be as shown in the picture below:
After updating the project properties, build it.
Creating a test project
Now that out pipeline component is ready, we need to test it. To do this, we'll create a new BizTalk project that will use our custom pipeline component. Add a new BizTalk Server project in our solution, and name it PipelineTest.
In this project, add a new "Receive Pipeline" item and name in UnzipTest.btp. Open the UnzipTest.btp and check that the toolbox doesn't show our custom pipeline component. To add the component to the toolbox, select Add/Remove Items (right click on the toolbox). A new window will show up (like in the picture below). In this window, select UnzipDisassemblerComponent.
Now that we have our component in the toolbox, drag it to the disassemble stage of the pipeline. Below this component, drag a
XmlDisassembler as well. Your pipeline should have the components as shown below:
Debugging the pipeline component
Now that our component is ready, we need to debug it. To debug a pipeline component, we'll need to use a tool that comes with BizTalk Server. This tool is called Pipeline.EXE, at it simulates the execution of a pipeline component for an input message.
Open the project properties of the pipeline component project, and select the Debugging tab. In Debug mode, select "Program", and click the "Apply" button. In the property "Start Application", use the path to the pipeline.exe tool. The most common path is shown below:
C:\Program Files\Microsoft BizTalk Server
In the command line, use the arguments below:
C:\Order.zip -c -m C:\%messageid%.xml
The first parameter represents the path to the pipeline file that we created in the PipelineTest project (you need to provide the complete path for this to work). The -d parameter represents the input document we'll use. In our example, the input document is a .zip file. The last parameters -c and -m, represent the output options (-c represents that the output should be shown in the console, and -m shows the output path of the generated messages).
After setting these parameters, set some breakpoints in the project and run it, you should see the complete steps of the execution of the pipeline.
As you can see, the creation of a custom pipeline component for BizTalk Server 2004 is a simple task, it just requires some extra coding time. Hope you like the article! :)
Mauricio Ritter lives in Brazil, in the city of Porto Alegre. He is working with software development for about 8 years, and most of his work was done at a bank, within a home and office banking system.
Mauricio also holds MCSD, MCSE, MCDBA, MCAD and MCT Microsoft certifications and work as a trainer/consultant in some MS CTEC in his city.
Mauricio also works in his own programming site, aimed to Brazilian Developers: http://www.dotnetmaniacs.com.br
In his spare time he studys korean language...