An SOA odyssey

Thursday, February 23, 2006

BizTalk Pipelines in the SOA

Here's an interesting problem that occurred on our team that we weren't aware of.

In our architecture all messages that in and out of BizTalk using custom SOAP headers based on WS-Addressing as I discussed in Message Standards.

What that means is that we implemented a custom pipeline component in C# that parsed our SOAP header and promoted the various fields we use to track messages such as MessageId and MessageStreamId. This pipeline is invoked when messages are received from outside sources such as our human workflow tool, Ultimus BPM Studio which posts to an HTTP receive location.

In the Exeucte method in our original code we used the following line to get the load the incoming document

xmlDoc.Load(inmsg.BodyPart.Data);

This code works fine as long as tracking is turned on in BizTalk. Once we turned off tracking in development we ran into problems where the properties were not being promoted like so:

There was a failure executing the receive pipeline:
"Compassion.BizTalk.Pipelines.Common.
SOAPHeaderReceivePipeline"
Source: "Compassion.BizTalk.Pipelines.Utilities"
Receive Location: "/UltimusResponse/BTSHTTPReceive.dll"
Reason: Pipeline component exception - Not implemented

Through a call to Microsoft (and subsequently through reading things like this) we discovered that we should be using the GetOriginalDataStream method in order to grab the message. This is the case since BodyPart.Data clones the incoming stream and the HTTP adapter uses the network stream which does not support cloning. Turning on tracking allows BizTalk to create a wrapper around the original message. And hence you can use BodyPart.Data.

So our new code looks as follows:

Stream s = inmsg.BodyPart.GetOriginalDataStream();
xmlDoc.Load(s);

Once we have the incoming message we can run a series of try/catch blocks as follows to grab the elements we need from the SOAP header and promote them.

// strip off the envelope and return
//just what is within the Body
System.IO.MemoryStream ms = new System.IO.MemoryStream
(Encoding.UTF8.GetBytes(xmlDoc.SelectSingleNode(
"//*[local-name()='Body']").InnerXml));
inmsg.BodyPart.Data = ms;

try
{
strMessageId = xmlDoc.SelectSingleNode(
"//*[local-name()='Header']
/*[local-name()='MessageID']")
.InnerText;
// remove the "uddi:" if present
strMessageId = strMessageId.Replace("uuid:","");
inmsg.Context.Promote(
"MessageId",
"http://schemas.microsoft.com/
BizTalk/2003/SOAPHeader".ToString(),
strMessageId);
}
catch {}

2 Comments:

Anonymous dheeraj said...

Hi,
I am a Biztalk developer working for a software company,I am currently working on creating Custom Biztalk pipelines.I have come across your article "BizTalk Pipelines in the SOA " , It was clear enough and gave me much information,can u please send me the xml file coz i am having problem in getting the node ( "//*[local-name()='Header'] /*[local-name()='MessageID']")) where can we find this type of data in xml file.if i can see the xml file then i can make out easily..as far as my knowledge is concerned ,i am able to see ( "//*[local-name()='Header'] /*[local-name()='MessageID']")) in schema while we promote the property as distinguished ..did u meant the same.. mail me dheeraj_bafna at yahoo.com

9:59 PM

 
Anonymous Morten Bock said...

Thanks for this! Saved my day :-)

6:55 AM

 

Post a Comment

<< Home