Charles Young

  Home  |   Contact  |   Syndication    |   Login
  144 Posts | 55 Stories | 362 Comments | 376 Trackbacks

News

MVP - Microsoft Most Valuable Professional

Twitter












Article Categories

Archives

Post Categories

Image Galleries

Alternative Feeds

BizTalk Bloggers

BizTalk Sites

CEP Bloggers

CMS Bloggers

Fun

Other Bloggers

Rules Bloggers

SharePoint Bloggers

Utilities

WF Bloggers

Richard Seroter of Microsoft has published a useful blog posting at http://blogs.msdn.com/richardbpi/archive/2005/10/27/485696.aspx in which he describes one technique for passing messages of any type through a BizTalk orchestration.   I would have liked to use comments to supplement what he has written with a couple of observations, but unfortunately his blog site does not appear to allow this.   Of course, I couldn't manage to keep to a couple of brief observations, so I run the risk of appearing to have 'hijacked' Richard's contribution.   I hope Richard won't hold this against me.

 

My first point has to do generally with BizTalk's approach to message typing.  One of the fundamental differences between message handling in pipelines and orchestrations is that, within pipelines, messages are treated as opaque type-less byte streams, whereas in orchestrations they are treated as strongly-typed objects.   This is a rather simplistic statement, and requires some qualification. 

 

The first thing to understand is that types are not really applied to messages.   They are applied to the content of message parts.   A message can have multiple parts, although most messages have a single part.   One part is designated the 'body' part of the message, and the type of this part is often thought of as the type of the overall message.   You see this clearly when you define a multipart message in an orchestration.   You type each part sepearatly.   For 'single-part' orchestration messages, this nuance is kept hidden from the developer, who thinks in terms of the message as a whole, rather than its single body part.   Maybe its just me, but I remember I found this inconsistency slightly confusing when I first encountered BizTalk.

 

Message part content is fundamentally handled as type-less byte streams within pipelines.   Content can be associated with type information, but only in an optional and rather loose fashion by using context properties to encode the type metadata.  BizTalk defines the BTS.MessageType property for this purpose.   For XML messages, this property is generally set by the XmlDisassembler component according to the following pattern:

 

            namespace#docElemName

 

If the XML document element (aka 'root element') exists in XML's global namespace, then BizTalk uses the element name alone.

 

Orchestrations, by contrast, treat message parts as strongly typed objects.   You set the type when you define a message in the Orchestration View in Visual Studio, and also when you configure messages in Orchestration ports.   For XML messages, the type is based on an XSD schema.  Behind the scenes, BizTalk auto-generates strongly typed message part classes by extending the abstract XSDPart class.   For non-XML messages, BizTalk extends the abstract DotNetPart class.   In both cases the generated classes wrap inner streams containing the content.   Note that both classes are derived from the abstract XLANGPart class.

 

This, then leads to my observations on Richard's posting.   Firstly, you can pass any messages through orchestrations in a strongly typed fashion.   If the message is not an XML message defined using an XSD schema, then create a .NET class to represent the type instead.   The inner content stream will be treated by BizTalk as a serialised instance of this class, so you need to design you class for serialisation/de-serialisation.  BizTalk uses .NET's XML serialisation by default, but for non-XML content you can use the .NET BinaryFormatter class, or alternatively create a custom formatter.  You can find out more about the role of formatters in .NET serialisation from the MSDN library.   As well as defining the class a serializable (use the Serializable attribute and, optionally, the ISerializable interface), you use BizTalk's CustomFormatter attribute to decorate your class in order to tell BizTalk which formatter to use.   You don’t use this attribute if you want BizTalk to use XML serialisation.

 

On at least one project, I have used an XML approach by auto-generating my classes using XSD.EXE (there are better alternative tools).   I manually amended one of these classes very substantially in order to build in enumeration facilities (I'll keep that story for another time) and other business logic 'smarts'.   I used XML serialisation attributes (XmlType and XmlRoot) to specify the namespace and document element names of the XML at the class level, and then typed my orchestration messages using these classes.   This is a very powerful approach indeed.   Thanks to the XML attributes, the orchestration sets up the correct subscriptions, just as if I had used an XSD schema (there is a bug in BizTalk Server 2004, fixed in Service Pack 1 that prevents the XmlType attribute from being used to define these subscriptions correctly).   I can then pass my message to helper code as an XLANGPart object and use the RetrieveAs() method to get the de-serialised instance of my class.   I can even assign new content using the LoadFrom() method.  Of course, these same methods work with non XML messages as well.  

 

If you create classes to handle non-XML content, you can use the class name as the MessageType specifier for subscription purposes.   You could create a pipeline component to set the MessageType property to this value in order to route messages to your orchestration.

 

So much for the typed approach.   Richard's posting describes one of two 'typeless' approaches.   In this model, you can pass message part content through orchestrations in an opaque fashion.   This can be useful when you don't want to process the message content in any way, and you don't want your subscriptions to be restricted by any consideration of the message type.   As Richard's example shows, you still have access to message context within your orchestration.   Richard uses the .NET System.Xml.XmlDocument class to define a message with a DotNetPart part.   When this same class is used to type a message in an Orchestration 'receive' port, the Orchestration engine suppresses the BTS.MessageType condition within the subscription it generates.   Hence messages of any type can be handled through this one port.

 

The second 'type-less' approach is to use the undocumented 'Any' XSD schema which Microsoft has pre-defined for you.   You will find this is always available when you select schema references when creating a message in Orchestration View or setting the message type in an Orchestration port.   The effect is much the same as when using System.Xml.XmlDocument.   Again, Orchestration receive ports suppress the generation of a MessageType condition within their subscriptions.  Internally, BizTalk defines the message with an XSDPart, rather than a DotNetPart, part.   there is therefore a subtle, and rather confusing difference in the two approaches.   The 'Any' XSD schema is strictly more appropriate when handling XML messages only.   The System.Xml.XmlDocument approach is a .NET, rather than an XSD, approach to typing the message part, and so is more appropriate when handling non-XML classes!   In reality, it makes little difference which technique you use, and you are best advised to follow Richard's example, as this is the only approach which is documented.

 

I can't resist adding one more nugget.   This comes with a serious health warning, and I am being rather irresponsible in handing this on.   There is an entirely undocumented, black-belt, technique you can use to access the raw content stream of a message part when using a type-less approach in BizTalk.   I have managed to get something of a reputation in SolidSoft in recent months for proposing the use of such dangerous techniques in production code - a suggestion which I am glad to report my wise and experienced colleagues have resisted gently but firmly!   So, if you really want some rope to hang yourself with, here is the technique.

 

Pass your 'type-less' message to some helper code using an XLANGMessage parameter in your C#/VB.NET/J#.   Then use the following code to access the stream (the XLANGMessage parameter is called 'wrappedMsg'):

 

    BTXMessage innerMsg = (BTXMessage)wrappedMsg.GetType().GetMethod

    (   "Unwrap"

      , BindingFlags.Instance | BindingFlags.NonPublic

    ).Invoke(wrappedMsg, null);

 

    string encodingName = "";

    System.IO.Stream contentStream = innerMsg.BodyPart.Value.GetStream(ref encodingName, true);

 

This code uses reflection to invoke the private Unwrap method defined on the abstract BTXMessage class, derived from XLANGMessage!   You must unwrap the inner message using this technique because the wrapper has been carefully constructed by Microsoft to prevent you getting the stream directly.   I make NO GUARANTEES about the safety of this approach.   If you are foolish enough to use it, you are on your own if BizTalk blows up in your face.

 

If you are wondering, I recently proposed the use of a similar technique in order to wrestle control of the MessageType property back from BizTalk.  The inability to control the setting of the MessageType property in message context for 'type-less' messages sent from orchestrations is a real problem in certain scenarios, and restricts the natural use of the subscription mechanism to implement more advanced patterns.  This is a deliberate restriction, explicitly coded into BizTalk, but I consider it unnecessary.   I haven't checked this out in BizTalk 2006, but I have seen no suggestion yet that this has been changed in the new version.   My proposal was understandably rejected, and we had to use an alternative loop-back adapter approach instead.   This was inelegant and a little inefficient.

 

[Additional Info] In BizTalk Server 2006, it is no longer necessary to consider using the above technique in order to set the MessageType property on a message within an orchestration.   This is because you can now invoke pipelines directly from within your orchestration.   For example, if you are processing an XML message, you can simply pass it to a Receive pipeline containing the XML Disassembler component.   It will be returned to you with the MessageType property set.   Alternatively, you could create a simple pipeline component to set the value of this property.

 

It is probably a little more efficient to use the undocumented technique, but I recommend staying within the confines of 'legality'.

posted on Thursday, October 27, 2005 10:48 PM

Feedback

# re: BizTalk Server 2004: Further observations on Orchestration message handling 10/28/2005 1:32 PM Richard Seroter
Charles, thanks for the follow up. Fixed comments on my own blog. Great points on alternate ways to do this as well. The next thing I wanted to try was taking this PDF blog and dumping it to a SQL table that has a binary type column. Fun stuff.

# re: BizTalk Server 2004: Further observations on Orchestration message handling 10/28/2005 1:41 PM Charles Young
Thanks Richard. I spent far too long at the beginning of this year looking at how to handle non-XML messages end to end in BTS, so this has been a pet subject of mine for a little while now. I've just come off the phone to a colleage of mine (the 'Arch Hacker' himself) discussing these very techniques. He is busy building a generic approach to extracting subsets of files from zip files within a pipeline disassembler and convoying them through an orchestration, so the typeless approach is very useful to him.

# re: BizTalk Server 2004: Further observations on Orchestration message handling 12/1/2005 3:03 AM Mick Badran
Hey Charles,

I'm trying to do something similiar except from a custom pipeline component I've added a series of properties to a multi part msg (rightly or wrongly?) - I'm now stuck trying to get access to those props tied to each individual msg part.

Paper back version:
- Composite envelope msg comes in - and we want to keep the envelope + innermsg intack.

- extract out 'payload' as xmldoc and store it as 'Part #2' of new outgoing pipeline msg

- derive bts schemas and enumerate promoted props + distinguished fields.

- store with Part#2 it's distinguished fields from it's schema + promote props to the envelope property storage.

- create a 3rd Part - fill it with an XMLDocument comprising of the extracted properties (name, namespace,xpath + value), this is for use to send to an external system that doesnt handle context props etc.

The reason for this approach is so - we deploy the 'core plumbing/framework' and the client can come along at a later date and deploy all their 'payload' schemas, marking distinguished fields etc and these are 'automagically' extracted into the 3rd document passed onto the external system.

I've added some props from the XLANGPart class - setproperty method (which is essentially a PropBag)....now it comes the time in Biztalk where I need to get access to those - ideally enumerate across the lot....but unfortunately it looks like I need to know the name.

Hope you're well and Any thoughts?

Mick




# re: BizTalk Server 2004: Further observations on Orchestration message handling 6/7/2006 3:39 PM Roman Ivanov
Charles, thanks for useful post. I tried your sample but run into exception "Specified cast is not valid." during cast XLANGMessage -> BTXMessage. I have tried typed and non-typed messages but all attempts were failed. Have you any idea why cast may fail?

# re: BizTalk Server 2004: Further observations on Orchestration message handling 6/8/2006 6:13 AM Charles Young
Thanks Roman

# re: BizTalk Server 2004: Further observations on Orchestration message handling 3/11/2007 2:26 PM Charles Young
Here is an XLang/s code snippet showing how to invoke the default XML receive pipeline from an orchestration message assignment shape. Assume that nextStepMsg is an orchestration message typed as System.XmlXmlDocument or Microsoft.XLANGs.BaseTypes.Any, and that the message content is XML. We want to send this message to the message box with a promoted BTS.Messagetype property. Because we are using one of the two 'open' message types, this won't happen automatically. We need to explicitly set the BTS.MessageType property on the message before submitting it to the message box. We are not allowed to do this directly in the orchestration. However, we can do this by first passing the message through the default XML receive pipeline which contains an XML Disassembler. Then, if we pass the message to a direct-bound orchestration Send port, and use a correlation set on the Send shape that contains BTS.MessageType, the MessageType property will be promoted.

This is an immensely useful technique. Anecdotally, I estimate that I have needed to do this in about 60% of all the BizTalk application I have created over the last three years or more. Life has therefore got a lot easier now that we can invoke pipeline components directly in BTS 2006.


// We can't do the following. MessageType is ReadOnly in orchestrations...
//nextStepMsg(BTS.MessageType) = "http://tempuri.com#NextStep";

// ...so invoke the default XML receive pipeline over the new message
recOutMsgs = Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline(typeof(Microsoft.BizTalk.DefaultPipelines.XMLReceive), nextStepMsg);

//NB. recOutMsgs is typed as Microsoft.XLANGs.Pipeline.ReceivePipelineOutputMessages

// Move to the first (and only) message and then assign it to nextStepMsg
recOutMsgs.MoveNext();
recOutMsgs.GetCurrent(nextStepMsg);


# re: BizTalk Server 2004: Further observations on Orchestration message handling 4/1/2008 10:34 AM Bembeng Arifin
Hi Charles,
Thanks for the tip on how to assign the MessageType property, you just save my day ;)

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: