I was on the MSDN Forums for the ESB Toolkit this morning, and came across a question from fellow BizTalk developer Barry Woods. He was asking about routing decisions in itineraries, so I threw in my two cents on the topic. Then I stepped back for a second and realized that there is a fantastic feature of the ESB Toolkit 2.0 that no one talks about.

This enigmatic feature stealthily crept into the Toolbox in Visual Studio, when you weren't looking. It takes up two slots in the toolbox, because two are necessary to compose its awesomeness. I'm referring to the "Itinerary Broker Service" and the "Itinerary Broker Output"; together they make up the feature that is the Broker Service. So what does it even do, and why do I need it? Well to get to that, first we need to take a step back and talk about how version 1.0 of the ESB Guidance handled itineraries, and how version 2.0 handles them. If you would rather not hear that discussion, click here to skip the fluff.

<implementationDetails>

In version 1.0 if the ESB Guidance, itineraries, represented as xml, were read as a sequential list of steps that needed to be executed. These steps were numbered sequentially just like items in an array. The Itinerary designer can serialize your model into this format, and will do so when you set the Export Mode of your itinerary model to Default.

However, if you switch this Export Mode to Strict, you will notice a few things change in the XML output. I would recommend you keep this XML output up in a separate tab as you're reading through the next section.

First of all, each messaging-based step (termed an Itinerary Service in ESB Toolkit lingo) has a stage attribute defined that correlates to the Container property of the model element in the designer.

Every step also has a businessName attribute associated with it which corresponds to the Name property of the model element in the designer. This name will be used in BAM tracking of itinerary execution.

Next you will notice that itinerary services can now have a PropertyBag associated with them that can be configured at design time for a different experience in each itinerary. This also means that you do not have to create a custom resolver each time you have an orchestration service that needs some business specific metadata that isn't related to what resolvers can already return.

Finally you will notice that each step has an id attribute, and a nextId attribute (with one exception that we will note later). This means that the services are no longer executed in a positional/sequential fashion, but instead are represented as a linked list that can be modified at runtime.

</implementationDetails>

Thus, we are brought back to the Itinerary Broker Service. This is the only service that allows us to select the next link in the chain, and thus change the entire path of execution that the itinerary takes. Right now the Itinerary Broker Service is only available within the pipeline, though designer support has already been built for you if you decide to create a custom orchestration-based broker service.

With minimal effort you will be able to have an itinerary that looks like this.

In order to begin using the Itinerary Broker Service, go ahead drag one on to your design surface, and then give it a unique name. Since this can only execute within the pipeline, you are either going to have an On-Ramp shape that connects into it, an Off-Ramp shape that connects into it (on the receive side of a two-way off-ramp), or another messaging service shape that connects into it. Make whatever connection makes sense for your scenario.

Now you will need to decide how many possible paths there will be through your itinerary. You don't have to account for every path a message will take to its destination, but rather which steps it will take to get there. For example, if you have two instances in which a message will have to be transformed once and then routed, that can be taken care of with a single path that includes a transform step and a routing step with a more dynamic resolver (e.g., the BRE resolver). If you have then another instance in which a message would have to be transformed twice before being routed, this would constitute another path through your itinerary. Once you decide how many paths you will need, drag an Itinerary Broker Outport on top of the Itinerary Broker Service you just added.

This will create smaller model elements that can be used to attach to other services. Which means that these allow this element to branch out just like you might have a decide shape branch in a BizTalk Orchestration. Go ahead and set the Name property on these to describe the path through your itinerary to which they will connect.

Next you will want to add a Resolver to the broker service, just like you would with any other Itinerary Service. In this case you will want to set the Resolver Implementation property to CONTEXT. This will return the context of the message being processed formatted like this. That's another tab you will want to keep open as we continue this discussion.

Normally resolvers are used for runtime resolution of endpoints, or transformations. Each resolver is given a configuration string, and returns a dictionary of key/value pairs as the result of its execution. Itinerary Services can then use the information in whichever way they please. In this case the Broker Service will use the very first key in the resolver dictionary (whatever it may be) as a value to switch on.

Put on your C# hat for a second and consider the following code:

string item = "spoon";
switch (item)
{
case "bowl":
bowl.Declare("too small");
bowl.Dump();
break;
case "spoon":
spoon.Declare("too big");
bowl.Dump();
break;
default:
break;
}

Now this is a silly example, but here we see that we are making a routing decision based on the value of item. The string named item in this example corresponds to the role of the Resolver in the broker service. The next thing we need to add is our cases. This corresponds to the Filters. So, go ahead and add a filter for each path you would like to take.

Name these filters according to the path that they will follow, or the condition on which they will be filtering. Next set the Filter Implementation property to XPATH. XPATH is the only filter that comes with the toolkit. Notice the Expression property of the filter. This expression will be evaluated against the first item returned by the resolver. In the case of the CONTEXT resolver, it will be this (which you should have open on another tab). So we could configure an expression that considers the inbound transport type for example:

//Property[@name='InboundTransportType']='FILE'

This will evaluate true for all messages that sent through a receive location with a file adapter. For those of you out there looking to build an orchestration-based broker service, filters will be serialized as properties in the property bag for the broker service itinerary step.

After you have configured your filters, you will have to return to your outports to configure which Resolver and Filter they are comparing by selecting them in the Filter and Resolver properties of the outport. Now there is a possibility, depending on the expressions you use, for two outports to be associated with a filter that will return true. In this case you can set the Order property of the outports to determine which one has precedence.

At this point, you will simply need to wire up your broker service outports to the proper services that should follow, and you will be good to go.

I have created a super simple sample itinerary that will switch based on the transport type, and route the message to a different location. You can find that sample here. Also be sure to check out our BizTalk screencasts and ESB screencasts.

The end for now.