In “BizTalk Pipeline Dreams, Part I,” a prototype called the Pipeline Channel Stack is described. Using ideas garnered from WCF, a prototype was built to allow you to more easily build “one-offs” or extend BizTalk Custom Pipeline solutions.
The prototype classes are arranged like the figure below.
All classes run inside a Custom Pipeline Component. PipelineBinding contains a stack of PipelineBindingElements. PipelineBindingElements are responsible for building the stack of PipelineChannels. PipelineChannels manipulate the incoming bytes from the BizTalk Port.
In this article, you will build on what you learned. First, you’ll see how to create your own Channels to add to the Pipeline Channel Stack and then you’ll be presented with additional ideas you can apply to your own solutions.
Building a PipelineChannel
In my earlier article, I discussed the role of the IPipelineChannel, MessageBodyHandler, and PipelineBindingElement. In the article “Build BizTalk 2004 Custom Pipeline Components to Process Non-XML Data,” I covered the use of Stream classes and Pipeline Components. So, instead of re-introducing these topics, I’m going to jump right into building a PipelineChannel and PipelineChannelBinding.
Building a PipelineChannel is straightforward. First, implement a Pipeline Channel class based on the IPipelineChannel interface and then build a PipelineBindingElement class to construct the PipelineChannel class. Listing 1 shows the IPipelineChannel interface functions.
Listing 1: The IPipelineChannel interface
public interface IPipelineChannel { PipelineMessage RetrieveMessage(); void AcceptInnerMessage(PipelineMessage message); }
TestPipelineChannel is the Pipeline Channel class in the sample solution implementing the IPipelineChannel interface. TestPipelineChannel copies a BizTalk Port’s Context into the incoming Pipeline message. Copying Context to an incoming or outgoing message is a classic BizTalk pipeline action. In fact, the first solution you build will likely involve working with the BizTalk Context.
In TestPipelineChannel, the AcceptInerMessage simply calls the WritePipelineContext function. The main parts of the TestPipelineChannel WritePipelineContext function appear in Listing 2.
Listing 2: The main parts of the WritePiplineContext function.
private PipelineMessage WritePipelineContext(PipelineMessage msg) { BizTalkContext ctxt; object contextValue; string strName; string strNamespace; MemoryStream stream = new MemoryStream(); XmlWriter writer; writer = SetupWriter(stream); writer.WriteStartDocument(); writer.WriteStartElement("Root"); CopyBodyToMessage(msg, writer); writer.WriteStartElement("BizTalkContext"); //Now Write the BizTalk Context ctxt = msg.BizTalkContext; for (int n = 0; n < ctxt.BizTalkMessage.Context.CountProperties; ++n) { contextValue = ctxt.BizTalkMessage.Context.ReadAt( n, out strName, out strNamespace); AddContextValueToWriter(writer, strName, contextValue); } writer.WriteEndElement(); //BizTalkContext writer.WriteEndElement(); //Root writer.WriteEndDocument(); writer.Close(); WriteStreamToFile(stream); ReplaceNewMessageFromStream(stream, msg); return msg; }
As you can see, WritePipelineContext makes prodigious use of the XmlReader and XmlWriter functions. In the XmlWriter class, WriteStartElement creates a new element in an XML document. Another call to WriteStartElement creates a child Element and so on in a hiearchal fashion, until a call to WriteEndElement closes the element.