Implementing messaging patterns
When working with BizTalk, the design considerations are very important. A bad design might result in poor performance, difficulty in changing the solution if the surrounding environment changes, and redundant code.
Working with canonical messages
One of the design patterns we should always try to meet (unless there is a good reason for doing otherwise) is the use of canonical messages inside BizTalk.
If BizTalk receives a message of type A and that message needs to be sent to another system and transformed to type B, we should make up our own internal message type instead of transforming directly from A to B. We do this, not by looking at the structure of either type A or B, but rather by making a type of the message that is independent of both types (type I).
This will require two transformations (Maps), one from type A to type I, and another from type I to type B.
We should also make sure that only canonical/internal messages hit the MessageBox
, so Map A to I should be applied on the Receive Port, and Map I to B on the Send Port.
This pattern has the following advantages:
If we receive messages from various partners/systems (type A1, A2, A3, and so on) and we map all of these different structures to a canonical type on the receive side, then the target system (type B) could change structure or format and we would only have to change the solution in one place, the transformation from the canonical type to B.
If more subscribers are interested in the message, and we make transformations directly from Message Type A to all of the desired formats of the subscribers, and we start receiving the messages in other formats, we would again need to make transformations from the new format to each of the subscribers instead of just transforming the new format to the internal format.
This is also the case when working with Orchestrations. Try not to use the Adapter or trading partner-specific Schemas inside the Orchestrations. Use internal versions of the messages instead. Use these internal versions inside the Orchestrations and then map from and to the internal Schemas in the Receive and Send Ports. By doing this, we don't have to recompile (let alone recode) an Orchestration if a Message Type on a Send or Receive Port is changed, or if the Adapter on a Send Port changes. The structure of the XML sent and received from the old and new messages would be different, but if we are only dealing with internal messages in our Orchestrations, only the Maps on the Send and Receive Ports would need to be changed.
Debatching
Another pattern we should try to implement, for most solutions, is the use of singular messages inside BizTalk. If we receive batches, such as several messages inside the same file, we should debatch them into individual items on the receive side of BizTalk (the Receive Pipeline).
The rule of thumb is that the solution should act the same way if we receive one large file containing 10 orders, as it should if we receive 10 orders in 10 files (one in each file).
BizTalk cannot handle the items individually if they are kept as a batch through BizTalk Server. If we receive orders, and some subscribers are only interested in orders containing a specific customer number, we would have no means (at least not with normal content-based routing) of subscribing to just those messages if all of them were kept inside a batch message.
There are other cases where keeping multiple items inside a batch and not debatching them makes sense. If a solution picks up a large batch of products, because full inventory is done once a day, and all subscribers are interested in seeing these products as a whole inventory report, we should not try to debatch them. Also, note that although BizTalk comes with great debatching functionality on the receive side, there is no automatic way of batching these items again if some subscribers need the inventory report as it was received and others need them individually. In this case, we would need to keep the batch inside BizTalk and then do some extra code (possibly using Orchestrations) to make debatched copies.
In other words, a debatched message is not easily assembled again with the same items in the same order.
Using the correct flow
We often have a decision whether to use a One-Way or Request-Response flow. The following table describes some of the scenarios where it makes sense to use one over the other:
Direction |
Type |
Usage |
---|---|---|
Receive |
Request-Response |
Used only if the caller submitting messages to BizTalk needs an answer back, such as |
Receive |
One-Way |
Used for cases other than the ones described in Request-Response |
Send |
Request-Response |
Used if BizTalk calls a system and needs an answer back from that system |
Send |
One-Way |
Used in all other cases |
It is important to not use Request-Response when only One-Way is needed. If calling a Web Service on a Send Port, it does not provide us with more reliability if we use a Request-Response port, instead of a One-Way port. The One-Way Port will, just as in a Request-Response scenario, wait for the service to finish and acknowledge that everything went well until the message is removed from the MessageBox
. Also, using Request-Response when not needed, will give us less performance and less flexibility, because a Request-Response message submitted to the MessageBox
can only have one subscriber.
Adapter independence
When designing a BizTalk Solution, we should try, whenever possible, not to make it so that code and/or logic is dependent on messages being received or sent using specific Adapters.
It might seem like a good idea to send files to an FTP Server using the %SourceFileName%
macro in the
Target File Name property, because we want to give the target server the same filename as the file had when we received it either by FILE or FTP. If this is a requirement, then this is, of course, how the solution should be made. However, try always to focus on the idea that the solution should also work if we changed the Adapter. If we start receiving messages from both a file folder and an Oracle database tomorrow, the %SourceFileName%
logic on our Send Ports will fail to work for the messages received from Oracle, simply because no original filename exists.
On the send side, people also tend to hardcode specific Adapter properties inside Orchestrations, which results in situations where changing the Adapter type requires us to change and recompile the Orchestrations.