BizTalk developers constantly complain that they are not able to assign values to correlation set values directly. Correlation sets are easy to initialise with values using promoted properties on messages, but very often, there is a need to correlate on data not contained within the message itself. Without a mechanism to do direct assignment, it is hard or impossible to implement design patterns which really ought to be simple to construct. This is especially the case where multiple orchestrations are collaborating on message processing.
In fact, it is perfectly possible to do precisely this kind of direct assignment, regardless of any values contained in, or promoted from a received message. Indeed, you can initialise correlation sets without using promoted message data at all. The approach, however, is a little obscure, and is not documented anywhere within the BizTalk documentation.
The technique is as follows:
- As per normal, create one or more property schemas that contain definitions of each of the properties you want to use in your correlation set.
- And now for the first obscure bit. In the schema editor, set the Property Schema Base property of each of your schema properties to "MessageContextPropertyBase". This setting allows you to access the defined properties within an orchestration, even though the data is not sourced from within the message itself. MessageContextPropertyBase is one of three classes used internally within the orchestration engine to represent message and message part properties. One of the other classes, MessageDataPropertyBase, is the default class, but can only be used in conjunction with schema-driven property promotion (the third class, 'PartContextPropertyBase, is used for properties on individual message parts, and is not supported in the BizTalk schema editor).
- For a specific correlated activity, identify each of the orchestrations which will be involved in passing correlated messages. In one of them, define a correlation type using the "MessageContextPropertyBase" properties defined above. Then create a correlation set of that type in each of the orchestrations (or simply pass correlation sets in as parameters if you are calling or starting orchestrations).
- In each orchestration involved in the correlated activity, configure receive and send shapes appropriately to initialise and follow your correlation sets. For each orchestration that creates its own correlation set, you will need to do initialisation in that orchestration.
- This is where the second (slightly) obscure bit comes into play. Identify each Send shape involved in the correlation activity, regardless of whether it is initialising or following a correlation set. For each Send shape, you need to add additional code in a message assignment shape before you reach the Send shape. This will be done in the message construction for the message you are sending. You may need to introduce new message construction and assignment shapes to handle this.
The required code will use the familiar context property assignemnt syntax of XLANG/s to create and assign values to your "MessageContextPropertyBase" properties. E.g.,
MyOutBoundMessage(CustomNamespace.CustomProperty) = "myCorrelationTokenValue";
When your message, complete with the context property values you have assigned, is passed to your Send port, the correlation set(s) associated with that port will be used appropriately with the context property data.
In many cases, you may have already received a message from another orchestration with some correlation value(s) already in its message context. In this case, you will typically want to assign values from the received message to the outbound message in order to correlate that message back to the first orchestration. Use syntax such as the following:
MyMessageToSendBack(CustomNamespace.CustomProperty)
= MyReceivedMessage(CustomNamespace.CustomProperty);
Note that as a nasty shortcut, you can also use the following to copy all context properties from one message to another:
MyMessageToSendBack(*) = MyReceivedMessage(*);
In this scenario, you might think that if you initialise a local correlation set on a receive shape, the values in that set would be automatically set on outbound messages when they pass to a 'following' send port. This is not the case, however. You must use code to assign values. You might also wonder if you really need to configure your send port to 'follow' the correlation set. After all, if a message contains the right tokens in its context when it is delivered to the message box, surely it will be correlated back to the first orchestration by subscription. However, the code show above will, by itself, write out values to message context as 'simple', (aka 'written'), properties. They will not be marked as promoted on the outbound message. Subscription only works with properties marked as promoted. When you send a message pre-populated with 'written' properties through a 'following' send port, the properties defined in the correlation type are changed to 'promoted' properties.
The use of MessageContextPropertyBase properties opens up a whole new level of flexibility in implementing architectural design patterns. Consider, for example, how easy it becomes to dynamically direct messages to specific orchestration instances or messaging Send ports on the basis of run-time lookups, or the time of day, or whatever, without having to, for example, introduce additional enveloped or 'canonical' message types in order to include your correlation tokens. With this approach you can now use correlation freely across multiple orchestrations, regardless of how they are invoked, and even as a general-purpose mechanism for fine-grained control of subscription predicates in non-correlation scenarios, without the problems many of us have encountered associated with correlation set initialisation.