Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Server

BizTalk 2010 Recipes : Messaging and Pipelines - Creating Custom Pipeline Components (part 2)

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
4/1/2011 9:20:50 PM

3. How It Works

BizTalk includes out-of-the-box functionality for processing messages within receive and send pipelines. However, situations may arise where custom processing of messages is required. For example, you may need custom message validation, processing of flat files, or formatting of messages to HTML that BizTalk does not natively support. Custom pipeline components offer incredible flexibility for preprocessing or postprocessing messages via send and receive pipelines. Additionally, custom pipeline components can coexist with native BizTalk pipeline components in the same pipeline.

In BizTalk solutions where message content or context determines routing, you may need to route messages based on the lack of existence of a property. BizTalk does not have the ability to route on the lack of property existence. However, you can use a custom pipeline component to create a property that is always part of a message. Rather than check for the existence of the property, you can check whether the property contains an empty string value. The solution that accompanies this recipe creates a custom pipeline component that creates a context property for every message that is processed by the component.

Creating custom pipeline components may seem like an extensive task due to the code required for hosting the component in a BizTalk pipeline, as well as setting the design-time properties. In actuality, there is a single method that contains the processing logic, and the remainder of the code supports the component design-time properties.

Your first task in creating a custom pipeline component is to create a project reference to the Microsoft.BizTalk.Pipeline.dll file contained in the main BizTalk installation folder. After you have added the appropriate project reference, you must consider the implementation of the custom pipeline component. There are three logical areas to a custom pipeline component to consider:

  • Attributes and class declaration

  • Design-time properties

  • Implementation of the four pipeline interfaces: IBaseComponent, IComponentUI, IPersistPropertyBag, and IComponent

The following sections describe each of these areas in more detail.

4. Attributes and Class Declaration

Consider how you plan on using the custom component, such as in a send or receive pipeline. Additionally, consider the pipeline stage in which you plan on implementing the custom component. The attributes and class declaration indicate to Visual Studio that the assembly is a custom pipeline component. If you do not properly identify that you are creating a BizTalk custom pipeline component, you will not be able to add the component to the Visual Studio toolbox or be able to add the component to a pipeline stage. Here is the header section from the sample code shown previously in Listing 1:

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Any)]
[System.Runtime.InteropServices.Guid("63ed4b26-63cd-4d29-9661-f584c94cf858")]
public class PropertyPromotionPipelineExample :
Microsoft.BizTalk.Component.Interop.IBaseComponent
, Microsoft.BizTalk.Component.Interop.IComponent
, Microsoft.BizTalk.Component.Interop.IComponentUI
, Microsoft.BizTalk.Component.Interop.IPersistPropertyBag


The sample custom component is identified, via the ComponentCategory attributes, as a pipeline component for use in any pipeline stage. Additionally, the class declaration specifies that four interfaces (IBaseComponent, IComponent, IComponentUI, and IPersistPropertyBag) will be implemented within the class. The GUID is required for use in COM interop with unmanaged code.

5. Design-Time Properties

Custom component design-time properties are exposed via public declarations and appropriate get/set methods. The following is the section of Listing 1 that demonstrates how two design-time properties are exposed.

#region Public Properties
// Display the following public properties for design time
public string CustomContextPropertyName
{
get { return m_propname;}
set { m_propname = value;}
}

// Display the following public properties for design time
public string CustomContextPropertyNamespace
{
get { return m_propnamespace;}
set { m_propnamespace = value;}
}
#endregion

6. Implementation of the Four Pipeline Interfaces

The final logical area required in the creation of a custom pipeline component is the implementation of four interfaces, as summarized in Table 1. The four interfaces provide the design-time and runtime implementations for the custom component and serve as a guide. Not all of the interfaces must contain code, and the IComponent interface contains the function that performs the message processing.

NOTE

If the custom component is to reside in either the Assemble or Disassemble pipeline stages, the component must also implement the appropriate assemble/disassemble interface.

Table 1. Interface Implementation
InterfaceDescriptionImplementation Notes
IBaseComponentProperties related to the basic information about the custom component.Contains three properties that enable the engine to retrieve the component name, version, and description.
IComponentUIDefines the properties for displaying the custom component in the design-time user interface as well as the validation rules for design-time properties.Contains two methods: one that allows the validation of the component's configuration and another that provides a pointer reference to the icon that will be displayed in the development tool set for the custom component. If null is set for the pointer, the default icon will be used.
IPersistPropertyBagCustom pipeline properties that are displayed at runtime when using the custom assembly in a pipeline.Enables a component to store and receive its configuration information.
IComponentDefines the method used by all pipeline components. Assembler/disassembler custom components implement their own interface.Contains the main function that performs the heavy lifting and processing of the inbound/outbound message. This method takes as parameters the pipeline context and incoming message.

6.1. IBaseComponent

IBaseComponent contains three read-only properties that return the description, version, and name of the component to the design-time environment and other tools interested in basic component information. Implementing the IBaseComponent is straightforward and requires implementing only the three read-only properties. Here is the section of the code in Listing 1 that demonstrates the implementation of the three properties.

#region IBaseComponent members defines Description, Name, and Version
public string Description
{
get
{
return "Sample Custom Pipeline Component";
}
}

public string Name
{
get
{
return "Sample Custom Pipeline Component";
}
}

public string Version
{
get
{
return "1.0";
}
}
#endregion


6.2. IComponentUI

IComponentUI serves to present the component icon in the design-time tool set. The two methods implemented in the IComponentUI are Icon and Validate. The Icon method provides a pointer to the graphic icon displayed in the design-time user interface. If no icon is specified, Visual Studio will display the default icon in the BizTalk Pipeline Components section of the Toolbox. The Validate method allows processing of any design-time properties. For example, if you have a custom design-time property that requires information, you can include validation rules within the Validate method to verify the design-time information entered.

The following portion of Listing 1 shows both the Validate and Icon methods. In the solution example included with this recipe, the default Visual Studio icon will be used, and no special validation rules are required for the specified user data.

#region IComponentUI members contains design time information
// Include a validate method used by BizTalk
public IEnumerator Validate(object obj)
{
IEnumerator enumerator = null;
// Return a null
return enumerator;
}
// We do not have an icon for this custom component
[Browsable(false)]
public System.IntPtr Icon
{

get
{
// No icon associated with this pipeline component
return IntPtr.Zero;
}
}
#endregion

6.3. IPersistPropertyBag

The purpose of the IPersistPropertyBag interface is to provide access to your object to unmanaged code. If you are familiar with .NET, then you may have used property bags in other projects. IPersistPropertyBag also allows access to design-time configuration values. There are four public methods that exist in the IPersistPropertyBag interface: GetClassID, initNew, Load, and Save. The GetClassID function must return a unique ID that represents the component. The initNew function can be used to establish structures (data, caching, and memory) used by the other IPersistPropertyBag methods. The final functions facilitate the loading and saving of property values. In the solution example accompanying this recipe, two additional methods were created to wrap the actual read/write functions of the property bag; however, the read and write functions could also be called directly from the Load and Save functions.

The following portion of the code from Listing 1 demonstrates the implementation of the four IPersistPropertyBag functions as well as the two helper functions.

#region IPersistPropertyBag members contains placeholders
public void GetClassID(out Guid classid)
{
// Return class ID of this component for usage from unmanaged code.
classid = new System.Guid("63ed4b26-63cd-4d29-9661-f584c94cf858");
}

public void InitNew()
{
// Initialization not implemented
}

public void Load(IPropertyBag propertyBag, Int32 errorlog)
{
// Load configuration property for component.
string val = (string)ReadPropertyBag(propertyBag,
m_propbagkey_customproprop);

if (val != null)
m_propname = val;
val = (string)ReadPropertyBag(propertyBag,
m_propbagkey_custompropropnamespace);
if (val != null)
m_propnamespace = val;
}

public void Save(IPropertyBag propertyBag
, Boolean clearDirty, Boolean saveAllProperties)
{



// Saves the current component configuration into the property bag.
object val = (object)m_propname;
WritePropertyBag(propertyBag,
m_propbagkey_customproprop, val);

val = (object)m_propnamespace;
WritePropertyBag(propertyBag,
m_propbagkey_custompropropnamespace, val);
}

private static object ReadPropertyBag(IPropertyBag propertyBag
, string propertyName)
{
// Reads property value from property bag.
object val = null;

try
{
propertyBag.Read(propertyName, out val, 0);
}
catch(ArgumentException)
{
return val;
}
catch(Exception ex)
{
throw new ApplicationException(ex.Message);
}
return val;
}

private static void WritePropertyBag(IPropertyBag propertyBag
, string propertyName, object val)
{
// Writes property values into a property bag.
try
{
propertyBag.Write(propertyName, ref val);
}
catch(Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
#endregion


6.4. IComponent

IComponent is the most important interface in the component, as it contains the processing logic for messages. This interface contains a single method, Execute, which takes two parameters. BizTalk calls the Execute method to process the message, and then passes the message and the context of the message as the two parameters. The following outlines the Execute method declaration and the two required parameters in Listing 1.

#region IComponent members contains the main implementation
public IBaseMessage Execute(IPipelineContext pContext
, IBaseMessage pInMsg)
{
// Create custom context property on message
pInMsg.Context.Promote(m_propname, m_propnamespace, string.Empty);
return pInMsg;
}
#endregion


The IPipelineContext parameter refers to the environment in which the component is running. For example, the IPipelineContext object contains pipeline property information, including the pipeline stage in which the component is running. The IPipelineContext object also contains a resource tracker, which cleans up objects. The IBaseMessage object contains the inbound message. The main purpose of the custom component is to perform some level of processing on the inbound message object.

The Execute method returns the IBaseMessage object, which represents all parts of the processed message (such as the message content and context). You may perform any type of message or context processing if you return the IBaseMessage object at the end of the function. When BizTalk processes messages through pipelines, it streams the messages, rather than passing the whole messages. Additionally, the message passed through the pipeline is a read-only data object. The solution example accompanying this recipe demonstrates only adding a context property and does not demonstrate updating the content of the message. You must perform the following steps if you plan to alter the message content:

  1. Create a memory stream object to hold the contents on the updated message or a copy of the inbound message. Remember that an inbound message is read-only, and you need a new container to perform updates to the inbound message. The new memory stream object is a container for the updated message.

  2. Process the inbound message stream. The easiest way of processing the inbound message is to copy the stream to a string and load the message into an XMLDocument. However, using an XMLDocument object does not perform well and is not recommended for a production-type solution. A better method involves using a stream reader to manipulate the inbound stream. Consider the following approaches for manipulating the inbound memory stream:

    • Use Stream.Read() as the primary mechanism for dealing with message content.

    • Use XMLReader.Read() as the secondary mechanism for dealing with message content.

    • Use the XML message in the DOM as a last resort option due to the performance hit. Specifically, if you're dealing with large messages, do not load the entire message into the DOM for processing.

  3. Set the message body part. After processing the message, you must return the updated message. If you used a memory stream object, you can set the return IBaseMessage.Data object to the memory stream object. Remember to rewind the updated memory stream object so you are passing the whole message and not the end of the memory stream. The pipeline processor will not attempt to rewind the stream, and you will receive a pipeline if the stream is not rewound.

  4. Add the memory stream to the resource tracker. If you used a new memory stream object, make sure to add the memory stream object to the IPipelineContext.Resource tracker for cleanup.

Pipelines are the first line of processing before a message is received by the BizTalk MessageBox or before the message is received by a target system. Out-of-the-box functionality supports the ability to perform straightforward processing of messages. There may be situations that require more complex processing, data validation, or interaction with .NET objects. In those situations, implementing a custom pipeline component offers the flexibility of adding processing logic within the BizTalk framework.

The main function required for implementing a custom pipeline component is the Execute function in the IComponent interface. The other interfaces serve for design-time and component interactions with the runtime engine.

Manipulation of the inbound message requires making a copy of the inbound message stream, as the inbound message stream is read-only. Before a memory stream can be returned to the IBaseMessage.Data object, it must be rewound, as the BizTalk pipeline engine does not perform this function. You should also clean up memory stream objects by adding the object to the pipeline resource tracker.

NOTE

There are several pipeline component creation tools available on the Internet that may be used to reduce overall coding effort.

Other -----------------
- Windows Server 2008 Server Core : Recording System Status Information (part 3) - Managing Event Information with the WEvtUtil Utility
- Windows Server 2008 Server Core : Recording System Status Information (part 2) - Triggering System Events with the EventTriggers Utility
- Windows Server 2008 Server Core : Recording System Status Information (part 1) - Managing System Events with the EventCreate Utility
- SharePoint 2010 : Reviewing the Scope of an Existing Site Collection
- SharePoint 2010 : Creating a Site Collection
- SharePoint 2010 : Understanding Site Collection Options
- BizTalk 2010 Recipes : Messaging and Pipelines - Creating Flat File Send and Receive Pipelines
- Windows Server 2008 Server Core : Configuring Directory Services - Working with Users, Groups, and Computers
- Windows Server 2008 Server Core : Managing the Active Directory Database with the NTDSUtil Utility
- Windows Server 2008 Server Core : Configuring Directory Services - Deleting Objects Using the DSRm Utility
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server