This post describes a way to perform debatching of a message after the original message has already been received and submitted to the BizTalk message box. This can be the case when for instance there are subscribers defined in BizTalk that subscribe to:
– The original message before debatching. To my knowledge, it isn’t possible to post both the original message and the debatched messages to the BizTalk MsgBox.
– A mapped version of the original message. To my knowledge, it isn’t possible to post both the original and the mapped messages to the BizTalk MsgBox.
So how do we handle a message in the BizTalk MsgBox, that needs to be debatched into seperate messages (without orchestrations)? Below a schematic representation of the solution used in this sample.
org = Original Message: contains some elements that occur 0..n.
arr = Array Message: a non-envelope message containing 0..n entities to debatch
env = Envelope Message: BizTalk envelope message with identical structure to array message
msg 1, msg 2, …, msg n = Debatched Messages
The steps in the above scenario:
1. A solicit-response send port has a subscription filter for the original message.
2. An outbound map is performed, transforming the original message into an array message.
3. Within the NamespaceReplacing pipeline component, the namespace for the array message is replaced with the namespace of the envelope message (this is in fact a transformation, though not via a BizTalk map).
4. The Loopback Adapter bounces the envelope message.
5. The XmlDisassemble component in the XmlReceive pipeline debatches (splits) the envelope message into its seperate messages.
6. The seperate messages are posted to the BizTalk MsgBox for further processing.
In order to make this work, there are some specific requirements to how the BizTalk schemas are setup. Below the representation of the used BizTalk schemas:
org = Original Message = OrdersRequest
arr = Array Message = InternalOrders
env = Envelope Message = InternalOrdersEnvelope
msg 1, msg 2, …, msg n = Debatched Messages = InternalOrder
Key thing here is that the array schema has an xml structure similar to the envelope schema. In fact, the envelope schema imports the array schema, and the envelope schema’s root element type is set to be the same as the root element type of the array schema. The only differences between the array schema and the envelope schema are:
– The root namespace.
– The envelope schema is configured to be a BizTalk envelope schema, while the array schema is not.
So why the Namespace replacing?
You may have noticed that the above could also be done by mapping from the original message to the envelope message directly, and not (have to) use the namespace replacing component. However, if you will try this, you will find that BizTalk doesn’t allow to map TO envelope schemas, when that map is configured as inbound or outbound map on a BizTalk physical port. You’ll get an error like (event id 5782):
The Messaging Engine failed while executing the outbound map for the message going to the destination URL "LOOPBACK://cfc0607f-e119-4e6b-ae34-8fae2a92b084" with the Message Type "http://Samples.Messaging.Schemas.OrdersRequest#OrdersRequest". Details:"Document type "http://Samples.Messaging.Schemas.InternalOrder#InternalOrder" does not match any of the given schemas. "
I will send a chocky bar of choice to the first one to find the solution for this error, wherever you are!
In order to work around this issue, I have used the Namespace replacer component to perform a 1:1 map from the array schema to the envelope schema by replacing the root namespace. A true BizTalk map, with all elements from the array schema ‘connected’ to the corresponding elements in the envelope schema, should have had the same effect (were it not for the fact that BizTalk doesn’t allow that on ports).
The Namespace replacer component has been implemented by using a lot of code from the Microsoft.Practices.ESB Namespace pipeline components (RemoveNamespace component). The Namespace replacer component takes two configuration parameters: OldNamespace and NewNamespace, and it just substitues the OldNamespace on all elements and attributes it encounters with the NewNamespace.
The XmlReceive pipeline configuration in this sample is pretty standard: debatching using an envelope schema, exactly like you would do on a ‘normal’ receive port.
This sample provides a way to debatch (or normalize) a message on a single port without the need for orchestrations. Think of it as a debatching port or normalizing port. There are some limitations to this approach:
– Error handling isn’t possible on a per-debatched-message basis. If debatching fails (on one debatched message), I assume you will get one suspended envelope message. When using orchestrations for debatching, the error handling could be done per debatched message. This could (to some extent) be mitigated by turning on Recoverable Interchange Processing on the XmlReceive Pipeline in combination with Failed Message Routing.
– …? any additions are welcome.
The sample runs on BizTalk Server 2006 R2. You can download it here.
BTW, If you’re interested in the namespace replacement only, you’re much better off writing a custom pipeline component that uses the Microsoft.BizTalk.Component.NamespaceTranslatorStream class, found in Microsoft.BizTalk.Pipeline.Components.