Microsoft BizTalk Server orchestrations allow parallel business execution branches, using the native Parallel Actions shape. However, the number of branches is static: to add an execution branch, you need to modify and recompile an orchestration.
1. When to Use Them
The behavior for Parallel Actions shapes doesn’t fit in scenarios where you know only at runtime the number of execution branches that you can spawn. An example is the travel agent service scenario described at www.w3.org/TR/ws-arch-scenarios/, where a travel agent requests in parallel a list of flights for each airline included in a customer list. This sample can be generalized to scenarios where a client application sends a request to a broker that splits it into individual requests for similar target systems; then the broker collects the responses from the target systems and aggregates them into a single response for the client (see Figure 1).
Figure 1. Sample broker implementation
The Recipient List pattern is explained by the Enterprise Integration Patterns site as the following:
A Content-Based Router allows us to route a message to the correct system based on message content. This process is transparent to the original sender in the sense that the originator simply sends the message to a channel, where the router picks it up and takes care of everything.
In some cases, though, we may want to specify one or more recipients for the message. A common analogy are [sic] the recipient lists implemented in most e-mail systems. For each e-mail message, the sender can specify a list of recipients. The mail system then ensures transport of the message content to each recipient. An example from the domain of enterprise integration would be a situation where a function can be performed by one or more providers. For example, we may have a contract with multiple credit agencies to assess the credit worthiness of our customers. When a small order comes in we may simply route the credit request message to one credit agency. If a customer places a large order, we may want to route the credit request message to multiple agencies and compare the results before making a decision. In this case, the list of recipients depends on the dollar value of the order.
In another situation, we may want to route an order message to a select list of suppliers to obtain a quote for the requested item. Rather than sending the request to all vendors, we may want to control which vendors receive the request, possibly based on user preferences.
How do we route a message to a list of dynamically specified recipients?
Define a channel for each recipient. Then use a Recipient List to inspect an incoming message, determine the list of desired recipients, and forward the message to all channels associated with the recipients in the list.
The logic embedded in a Recipient List can be pictured as two separate parts even though the implementation is often coupled together. The first part computes a list of recipients. The second part simply traverses the list and sends a copy of the received message to each recipient. Just like a Content-Based Router, the Recipient List usually does not modify the message contents.[]
This section describes a dynamic parallel implementation of this pattern with a BizTalk orchestration.
An alternative approach would have been using the Publish-Subscribe and Message Filter patterns. We don’t describe here this alternative approach, because this implementation could be more resource consuming in terms of database queries to resolve the filter conditions, and more error prone while setting filter conditions on the channels.
2. Broker Implementation Overview
Our implementation of the broker requires using two different orchestrations.A parent orchestration builds the list of recipients, based on the received document. The parent orchestration uses the Start Orchestration shape to launch a child orchestration for each recipient. The child orchestration executes the actual flow of messages with the recipient. We assume that all the recipients share a common workflow model and schema documents; otherwise you wouldn’t need such a dynamic invocation model, because a manual activity would be needed to introduce each additional recipient! The child orchestration makes use of dynamic port binding to send messages to each different recipient.
The parent orchestration collects the results returned by each child and builds an aggregated response document. The parent orchestration makes use of a self-correlating binding port to receive the responses from the started child orchestrations.
In Exercise 1, we concentrate on the general design and on the orchestration mechanisms involved in the dynamic parallelism implementation; we don’t give a complete implementation sample including schemas, maps, ports, and helper Microsoft .NET Framework objects. A working knowledge of the basic orchestration development tasks is required.
EXERCISE 1: CREATING THE IMPLEMENTATIONCreate the Parent Orchestration The following are the steps required to create the parent orchestration as shown in Figure 2 for the solution within Visual Studio Figure 2. Parent orchestration main blocks
Next, create the SpawnChild loop whose steps are defined here and shown in Figure 3. Figure 3. Parent orchestration loops
Once the preceding steps are completed, the final step is to create the wait responses loop as defined here:
Create the Child Orchestration Once the parent orchestration is created, the next step is to create the child orchestration. The steps for this are defined here and the orchestration is shown in Figure 4. Figure 4. Child orchestrationYou will reuse the Recipient Request and Recipient Response schemas defined before.
Bind the Parent Orchestration to the Child Orchestration To complete the exercise, you need to add the following additional configuration to the parent orchestration:
|
[] Alternatively you could use a BizTalk map to create the new message—either approach will work.
[] This can be accomplished a number of ways. A potential choice would be to use an aggregating pipeline, collect all the messages to be aggregated, and call the pipeline with the array of messages. An implementation of an aggregating pipeline is given in the BizTalk SDK under the Program Files\Microsoft BizTalk Server 2009\SDK\Pipelines directory. Another choice would be to create a .NET component to accept the messages as they are received and aggregate them together.
[] The code for the Expression shape will look something like PortToTarget(Microsoft.XLANGs.Base-Types.Address) = “Http://wsOrders/Interface.asmx”.
[] This implementation requires that the address of where the messages are to be sent is known ahead of time. In the original message that was received by the parent orchestration, an element must exist that contains this address. This value must be promoted into the context via either the schema definition or a distinguished field.
The previous exercise shows you how you can use orchestrations to solve a real-world problem. Let’s look at another issue that often arises when processing messages—dealing with order.