November 24, 2014
Hot Topics:

BizTalk Pipeline Dreams, Part I

  • June 29, 2007
  • By Jeffrey Juday
  • Send Email »
  • More Articles »

Custom Pipeline Component

For more detailed coverage of Custom Pipeline Components, review "Build BizTalk 2004 Custom Pipeline Components to Process Non-XML Data." I'm going to give an overview of Custom Pipeline Component development.

Here are the main Custom Pipeline Component development ideas.

  • Custom Pipelines, though managed, run inside an unmanaged environment. Thus, they must contain the appropriate attributes.
  • A Custom Pipeline must implement a number of .NET Interfaces and attributes.
  • Custom Pipelines are activated when the Execute function is invoked. Execute contains two parameters: IBaseMessage and IMessageContext. IBaseMessage contains, among other things, a byte Stream representing the data from the BizTalk Port of the Pipeline.
  • Custom Pipelines are used inside of Pipeline Components. To use a Custom Pipeline Component, you must copy the Pipeline Component and supporting classes to the Pipeline Components folder and add the Component to the Visual Studio toolbox.
  • Depending on Interfaces implemented and the attributes added by the Custom Component, a Custom Pipeline Component can be dropped into any number of stages in a Pipeline.

As stated earlier, the Execute function activates the Custom Pipeline Component. The body of the Execute function appears below:

public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{

   BizTalkMessageIdentification idValues =
      new BizTalkMessageIdentification("MessageType",
      @"http://schemas.microsoft.com/BizTalk/2003/system-properties",
      "TestMessage");
   //this is where you add special handling for the message body
   BizTalkContext bizTalkContext = new BizTalkContext(pc, inmsg,
                                                      idValues);
   PipelineExecutionContext exec;
   PipelineBinding binding = new PipelineBinding(bizTalkContext);
   StandardPipelineConfiguration config =
      new StandardPipelineConfiguration();

   exec = binding.GetExectutionContext();

   config.Init(bizTalkContext, "here");

   config.PopulateBinding(binding);

   return exec.Run();
}

As you can see, Execute invokes a number of classes. I'll explain what each class does, starting with the BizTalkContext.

BizTalkContext

BizTalkContext is a wrapper for the IBaseMessage and IMessageContext parameters on the Execute function. BizTalkContext also handles PipelineMessage creation. Wrapping Execute parameters and handling PipelineMessage creation serves the following purposes.

IBaseMessage and IMessageContext will be used by the layers in the Stack. Wrapping the classes facilitates passing the classes throughout the Stack. Also, at some point in the future you may want to include auditing or restrict direct control to the Execute parameters.

PipelineMessage is passed throughout the Stack. I wanted to restrict PipelineMessage creation to the classes in the core assembly. So, I made the PipelineMessage constructor internal. Somewhere, though, I needed to provide a mechanism for other Stack classes to create a new PipelineMessage. PipelineMessage and the Execute parameters purpose are intertwined, so I housed their creation in BizTalkContext.

Now, turn to the role of PipelineExecutionContext.

PipelineExecutionContext

PipelineExecutionContext is the "command and control" part of the Pipeline Channel Stack. PipelineExecutionContext works closely with the PipelineBinding class, invoking Stack building functions on the PipelineBinding and iterating through the Stack created by the PipelineBinding.

Run is the sole method in the class and to a great degree Run "is" the Pipeline. The body of Run appears below.

public IBaseMessage Run()
{
   PipelineMessage msg;
   PipelineChannelContext context;

       PipelineChannelTrace.WriteLine("Run Started..");

   _binding.Build();    //Assemble the channel stack

    //reach into bottom of the stack
   context = _binding.ChannelStack.Contents[0];

   msg = context.RetrieveMessage();    //Get the bottom message

   //Now pass the message through the stack
   for (int n = 1; n < _binding.ChannelStack.Contents.Count; ++n)
   {
      context = _binding.ChannelStack.Contents[n];

      context.AcceptInnerMessage(msg);

      msg = context.RetrieveMessage();
   }

   PipelineChannelTrace.WriteLine("Run Ended..");

   return msg.ApplyMessage();
}

As you can see in the loop, each member in the Stack consists of a PipelineChannelContext class. PipelineExecutionContext passes a PipelineMessage into the PipelineChannelContext invoking AcceptInnerMessage and then pulls a new PipelineMessage or transformed PipelineMessage out of the PipelineExecutionContext invoking RetrieveMessage.

PipelineChannelContext is really just a thin wrapper around a class implementing the IPipelineChannel interface. I wanted to include the ability to trace through Stack execution without relying on the developer, so I wrapped the IPipelineChannel in PipelineChannelContext.

I've mentioned PipelineBinding quite a bit. Now, I'm going to show you what it does.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel