You find yourself writing custom pipeline components in nearly all BizTalk related projects. So this is a common activity. And usually it will mean eventually you will need to extract data from the message coming on the wire using XPath statements.
The issues you usually face while trying to extract data from BizTalk massages is that the message stream would not seekable. And another problem is how to do this data extraction with the minimal memory footprint (no XmlDocument L) and also as fast as possible.
I created mainly two functions that I use commonly for these tasks. The first one is to get the stream from the message and create a seekable one to be used later on.
private Stream GetMessageStream(Microsoft.BizTalk.Message.Interop.IBaseMessage msg, Microsoft.BizTalk.Component.Interop.IPipelineContext context)
Stream stream = msg.BodyPart.GetOriginalDataStream();
ReadOnlySeekableStream readStream = new ReadOnlySeekableStream(stream);
if (context != null)
msg.BodyPart.Data = readStream;
stream = readStream;
The second method is the one that would perform the data extraction as follows.
private string ExtractDataValueXPath(Stream MsgStream, string MsgXPath)
XmlReaderSettings settings = new XmlReaderSettings()
ConformanceLevel = ConformanceLevel.Document,
IgnoreWhitespace = true,
ValidationType = ValidationType.None,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
CloseInput = false
XmlReader reader = XmlReader.Create(MsgStream, settings);
string strValue = null;
XPathDocument xPathDoc = new XPathDocument(reader);
XPathNavigator xNavigator = xPathDoc.CreateNavigator();
XPathNodeIterator xNodes = xNavigator.Select(MsgXPath);
if (xNodes.Count != 0 && xNodes.MoveNext())
strValue = xNodes.Current.Value;
As you can see I am using XPathDocument with a XmlReader to perform this as fast as possible.
Thanks you rock!
How do you apply the global properties on your extracted message?
Do I Need to pass complete MsgXPath or only node name .. Can you please help