Click here to Skip to main content
Click here to Skip to main content
Go to top

Implementation of a Message Broker on BizTalk

, 13 Jun 2011
Rate this:
Please Sign up or sign in to vote.
This article describes an implementation on BizTalk 2006/R2/BizTalk 2009 where a received message is split and sent to many different destinations.

Introduction

This article describes an implementation on BizTalk 2006/R2/BizTalk 2009 where a received message is split and sent to many different destinations. The number of destinations is not known before runtime. BizTalk reads information about the receivers from the message and sends a message to each target system. BizTalk receives a response from each of the targets and aggregates them into a response message which is sent back to the sender.

One example where this implementation can be used is when a web application needs to compare prices of a product from different providers. The web application sends a request to the broker and receives back a response that includes the prices from the different providers.

Overview

This implementation contains two different orchestrations. A parent orchestration receives the message, counts the number of receivers, creates a copy of the message, and starts a child orchestration for each recipient.

The child orchestration reads the receiver's ID from the message and uses that to find transport information and address from a database. All information about the receivers is stored in a database, only the receiver's ID is included in the message. A separate .NET assembly is used to get this information. The child orchestration configures a dynamic send port based on the information about the receiver, and sends the message to the target system. It also receives a response from the target system.

The parent orchestration uses a self-correlating binding port to receive the responses from the child orchestration. It adds all responses into one message and when all responses are received, it calls a pipeline to aggregate the messages into an envelope and then it sends the envelope with all responses back to the sender.

The messages

There are four different messages included in this implementation, and each has its own schema. One schema is for the main request which is received by the broker, and one for the main response which is sent back to the sender. There is also one schema for the recipient request which is sent to the target systems and one for the recipient response that the target systems send back to the broker.

The parent orchestration

In this case, the message that BizTalk receives contains one record for a main receiver and one or many records for copy destinations. The message is received by a static receive port and a receive shape activates the orchestration. The orchestration's Transaction Type is set to be Long Running and the Timeout is set to be one day.

Count the receiver destinations

The first thing to do is to count the copy destinations. This is done in an expression shape. The total number is stored in a variable named intTotalRecipients.

intTotalRecipients = System.Convert.ToInt32(xpath(msgMainRequestIN,
  "count(/*[local-name()='Request' and namespace-uri()='http://Stm.MessageBroker" + 
  ".Schemas.MainRequest']/*[local-name()='CopyDest' and " + 
  "namespace-uri()='http://Stm.MessageBroker.Schemas.MainRequest'])"));
intRecipientNumber = 0;

ParentOrch01.jpg

Construct an individual message for each destination

The individual messages are created in a loop which runs as long as the variable intRecipientNumber is less than or equal to the total number of recipients. The variable intRecipientNumber is used to hold the current recipient and it is increased by one at the end of the loop. First, a message is created for the main destination. This is done in a construct shape which simply maps the received main request to the individual recipient request if intRecipientNumber is equal to 0.

For each copy destination, a helper message is first constructed. This message is based on a simple schema with only two fields, and it contains the value of the current recipient and the value of intRecipientNumber. (The other field is not used.) Both are distinguished fields. The message assignment expression looks like this:

xmlDocSplitHelper.LoadXml("<splitmainrequesthelper " + 
  "xmlns:ns0="http://Stm.MessageBroker.Schemas.SplitMainRequestHelper" />" + 
  "<recipientnumber />10</recipientnumber /><recipientstotal />" + 
  "10</recipientstotal /></splitmainrequesthelper />");
msgSplitMainRequestHelper = xmlDocSplitHelper;
msgSplitMainRequestHelper.RecipientNumber = intRecipientNumber;

This message is, together with the main request, used as input in the mapping to the recipient request in the construct shape where the recipient request is constructed. (A map with two input schemas can be created when choosing to create a new map in a transform shape.) In this map, Index functoids are used to get the values from the correct copy destination record. Input to the Index functoids are the value from the helper message (the current value of intRecipientNumber) and the value from the copy destination record (copy destination ID).

At this point, the individual request is correctly constructed:

ParentOrch02.jpg

Start the child orchestration and wait for responses

A self-correlating binding port is used to receive the responses from the child orchestration. The port identifier is ReceiveFromChildPort and the port type is FromChildPortType. This port and the recipient request that is constructed above are used as parameters when starting the child orchestration. The orchestration engine then generates a correlation token on the message that is particular to the orchestration instance. This provides the capability of getting responses back to the parent orchestration instance without using a correlation set.

The variable intRecipientNumber is set to 0 and a new loop is used to receive responses through the port ReceiveFromChildPort. The intRecipientNumber is increased at the end of the loop and the loop runs until intRecipientNumber is equal to intTotalRecipients and all the responses are received.

ParentOrch03.jpg

Aggregate the responses and send a response back to the sender

The responses that are received are added to a variable MessagesToAggregate of type SendPipelineInputMessages in the expression shape in the loop above.

MessagesToAggregate.Add(msgRecipientResponse);
intRecipientNumber = intRecipientNumber + 1;

When the loop is finished, this variable contains all the responses. Then a new message AggregatedMessage of type XmlDocument is constructed. This is done by calling a send pipeline to aggregate the responses. This send pipeline contains an XMLassembler where the main response schema is specified as an envelope schema and the recipient response schema is specified as a document schema. To make this work, it is important that the envelope schema contains an Any Element to include the recipient responses. The expression in the construct shape to construct the AggregatedMessage and call the send pipeline looks like this:

AggregatedMessage = null;
Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteSendPipeline(
  typeof(Stm.MessageBroker.Pipelines.XMLAggregate),MessagesToAggregate,AggregatedMessage);

The AggregatedMessage is then sent back to the sender.

ParentOrch04.jpg

The child orchestration

The child orchestration has two orchestration parameters: a message parameter which is the recipient request message, and a port parameter which has the same port type as the self-correlating binding port in the parent orchestration, FromChildPortType.

Get information about the receiver and configure the dynamic send port

All information about the different receivers is stored in a database. In this example, there is a table named Partners that contains the fields PartnerID, PartnerName, and TransportType. Then there is a table for each possible transport type. A FILEInfo table contains all the necessary information for configuring a dynamic FILE port for the partners with the transport type FILE. A similar table also exists for the partners with transport type SMTP. An external assembly helps to get this information from the database. This assembly provides a Transport object, and in the orchestration, there is a variable named objTransport of this type. This assembly is not a part of the broker, so no explanation will be given in this article. However, the source code is included in the download. Mind that this assembly is just a simple example of how to get this data.

The first expression shape gets the receiver's ID from the distinguished field and initializes the objTransport object.

strPartnerId = msgRecipientRequest.Receiver.Id;
objTransport.InitializeByPartnerId(strPartnerId);

When calling the InitializeByPartnerId method, the external assembly looks up in the Partners table to find the correct transport type. It then looks up in the correct table and fills the objTransport properties with information. The objTransport object contains properties for all transport types.

Based on the objTransport.TransportType property, a new recipient request message is constructed and the dynamic send port is configured. In the case of SMTP, the message assignment shape in the construct shape looks like this:

SndRequestTargetPort(Microsoft.XLANGs.BaseTypes.Address) = objTransport.Address;
SndRequestTargetPort(Microsoft.XLANGs.BaseTypes.TransportType) = objTransport.TransportType;

msgOUT = msgRecipientRequest;
msgOUT(*) = msgRecipientRequest(*);

msgOUT(SMTP.SMTPHost) = objTransport.SMTPHost;
msgOUT(SMTP.SMTPAuthenticate) = objTransport.SMTPAuthenticate;
msgOUT(SMTP.EmailBodyTextCharset) = objTransport.EmailBodyTextCharset;
msgOUT(SMTP.EmailBodyText) = "Message from BizTalk";
msgOUT(SMTP.MessagePartsAttachments) = 1; // Message Body as attachment
msgOUT(SMTP.Username) = objTransport.Username;
msgOUT(SMTP.Password) = objTransport.Password;
msgOUT(SMTP.From) = "stmbiztalk@gmail.com";
msgOUT(SMTP.Subject) = "Test from biztalk";

ChildOrch01.jpg

The constructed message is then sent through the dynamic send port to the target system.

Receive the response from the target and send it to the parent orchestration

The send shape that sends the message to the target initializes a correlation set based on the MsgId in the recipient request and the OriginalMsgId field in the recipient response. These are promoted fields. The recipient response needs to contain the original recipient request's MsgId in order to correlate. (This MsgId is made unique for each recipient in the mapping from the main request to recipient request.) A receive shape receives the response and follows up this correlation set.

A send shape sends the response back to the parent orchestration through a send port with Port Type FromChildPortType. Note that this is the same port type that was defined and used to receive responses in the parent orchestration and also used as port parameter in the child orchestration.

ChildOrch02.jpg

General exception handler

A general exception handler is added in order to send a constructed response back to the parent orchestration if an error occurs or if no responses are received within the timeout limit. Catching exceptions can be done in several ways. In this case, a simple response with some error information is created and sent to the parent orchestration.

Test and installation

All necessary source code to test this implementation is included in a solution in the download. The database is not included, but it is easy to see how the database is designed in the source code to the external .NET assembly.

The .NET assembly needs to be built and installed in GAC. All other projects in the solution need to be deployed to BizTalk.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

No Biography provided

Comments and Discussions

 
QuestionGreat idea and job PinmemberSalam Y. ELIAS22-Jun-11 23:10 
AnswerRe: Great idea and job PinmemberSteinar Moen from Norway27-Jun-11 22:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140922.1 | Last Updated 13 Jun 2011
Article Copyright 2011 by Steinar Moen from Norway
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid