Tuesday, November 6, 2012

One-way WCF service from BizTalk orchestration returns 200 OK on an invalid message

Today I ran into some weird behaviour of the WCF service that is generated by the WCF Service Publishing Wizard of BizTalk.

I have an orchestration that has a receive port but no send ports. This means that when I generate a service from this orchestration, it will result in a one-way service.

In the xsd for the incoming message, there is a restriction on a field. Something like this:

<s:simpletype name="FIELDTYPE">
  <s:restriction base="s:string">
    <s:enumeration value="Value1" />
    <s:enumeration value="Value2" />
  </s:restriction>
<s:simpletype>

When I send a valid message to the WCF service, the message is neatly delivered to the BizTalk Messagebox, as expected, and the orchestration can process it. The service returns HTTP status code 202 Accepted. Nice.

But when I send a message that contains

<FIELD>Value83</FIELD>
(which by its restriction makes this an invalid message) the message never finds its way to the message box. So it doesn't result in a suspended message, nor does it show up in the Tracked Message Instances. It just disappears.

This isn't really a problem, as after all, it was an invalid message. But it does look a bit weird to see the service return HTTP status code 200 OK....

Thursday, September 13, 2012

Problem with LoadXml in BizTalk

I ran into a problem where an XML was written to flat file but instead of the flat file containing one line of data, it contained multiple lines. Or in other words: there were unwanted line-breaks in the line.

It took me a while to figure out where they came from, but finally I found this: I had an input string containing the XML like this:

<root><node></node></root>

In BizTalk inside an expression shape, I had code like this:

xdoc.LoadXml(myInputString);
someMessage = xdoc;

Here someMessage contained:

<root>
  <node>
  <node>
</root>

So <node> contained a line-break...

The solution was simple: set PreserveWhitespace to true like this:

xdoc.LoadXml(myInputString);
xdoc.PreserveWhitespace = true;
someMessage = xdoc;

Thanks to Scott Colestock's blog I found this.

BTW When the input XML was like this:

<root><node /></root>
the problem never occured...

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.