Tuesday, April 24, 2012

Promoting MessageType property on untyped messages

Imagine the following scenario: you have a number of orchestrations in your BizTalk solution that are all activated by a certain messagetype. And there is one special orchestration that, using some procedure, generates those messages. The idea is that this special orchestration writes the generated message to the messagebox and that way the associated orchestration will be started. Sounds easy, right?

Alas, not everything in life is easy... Here, the problem is your generated messages are untyped, that is, the message type in your orchestration is System.Xml.XmlDocument. When you write this message to the messagebox using a Direct send port, it has no promoted properties which are needed for the routing, so you will end up with a 'Routing Failure' error.

The only property we really need to promote is BTS.MessageType. And here's the problem: within an orchestration you can promote almost every property... except BTS.MessageType, which is read-only! Grrrr.....

You can work around this by writing the message to some file location and then have a receive location using the XMLReceive pipeline. Fine, but obviously we don't want that. We want to fix this in our own orchestration! Can we do this? To quote Mr. Obama: Yes, we can!

In the work-around we use the XMLReceive pipeline. That pipeline promotes the properties, including BTS.MessageType! And BizTalk allows you to invoke a pipeline from within an orchestration! So let's do this!

Alas there is one minor problem here. Invoking a pipeline from within an orchestration's shape forces you to use Atomic scope. Which we don't want, do we? We can avoid this by not invoking the pipeline directly from the orchestration's shape but by using the following class-method:

using Microsoft.XLANGs.BaseTypes;
using Microsoft.XLANGs.Pipeline;

namespace RonaldLokers.Blogspot.Com.PropertyPromotor
{
    public class Helper
    {
        public static void DetermineMessageType(XLANGMessage message)
        {
            ReceivePipelineOutputMessages pipelineMessages =
              XLANGPipelineManager.ExecuteReceivePipeline(
                typeof(Microsoft.BizTalk.DefaultPipelines.XMLReceive)
                  , message);
            pipelineMessages.MoveNext();
            pipelineMessages.GetCurrent(message);
        }
    }
}

You will need to add references to Microsoft.BizTalk.DefaultPipelines, Microsoft.BizTalk.Pipeline, Microsoft.XLANGs.BaseTypes, Microsoft.XLANGs.Engine and Microsoft.XLANGs.Pipeline to your project. The dll's can all be found in your Microsoft BizTalk Server 2010 folder.

So now we can use this method in our orchestration: create a variable xdoc of type System.Xml.XmlDocument, create a message msgUntyped of the same type, create a Construct Message shape, and use a Message Assignment shape. In that last one, use the following code:

xdoc = new System.Xml.XmlDocument();
xdoc.LoadXml(your xml input here);
msgUntyped = xdoc;
RonaldLokers.Blogspot.Com.PropertyPromotor.Helper.
    DetermineMessageType(msgUntyped);

And the message has promoted properties!

Now there's one last trick... if you send this message using a Direct send port, it will still drop the promoted properties. Why? Beats me! Probably the guys at Microsoft figured that a message of type System.Xml.XmlDocument doesn't need properties. So how can we avoid that?

Create a correlation set, based on a correlation type with Correlation Properties 'BTS.MessageType'. On the send shape in your orchestration, use this correlation set as the Initializing Correlation Set. That way, you force BizTalk to maintain the promoted properties for that message.

And there you go! That's what we need to do to go from untyped message to typed message in the messagebox.

4 comments:

  1. Hi Ronald,

    Fantastic post - thanks. I've been working through a similar issue for the past day or so, and at least now I understand why it's not working.

    Shame about the 'feature' whereby the promoted properties are excluded when the message is sent directly to the messagebox. Oddly I found the same behaviour even if I was sending to a bound FILE send port rather than a direct bound port.

    Thanks again for the post!

    Nick

    ReplyDelete
  2. Isn't this Post a GEM........A truely LifeSaver...Thanks Buddy

    ReplyDelete
  3. Ronald, thank a lot for the time and effort that you have spent into this article. The solution works perfectly. This article is a key to efficient use of direct bound ports with XmlDocuments and has also helped me to better understand how BizTalk handles this stuff.

    ReplyDelete
  4. You just saved my bacon. What is it about MoveNext() and GetCurrent() that promotes MessageType? Whatever, it works. Thank you!

    ReplyDelete