Overstanding the ESB Itinerary Cache

Overstanding the ESB Itinerary Cache

If you Google-Bing the ESB Itinerary Cache you come across a definition of the likes: “ The itinerary cachingpipeline component for use in Solicit-Response send ports.”

and…

Messages submitted through the ESB itinerary on-ramp can be either a one-way or two-way (request-response) itinerary. To support request-response itineraries, the itinerary mechanism must provide caching for BizTalk dynamic Solicit-Response send ports.

The Itinerary Cache pipeline component persists the itinerary stored in the outbound message and reapplies it to the response message returned to the send port after the service call is complete. This allows the itinerary service to process and execute other services defined after the current service in the itinerary.

The ESB Itinerary Cache pipeline component caches the itinerary during the period that the message is in the Send Transmit pipeline process cycle. The component then retrieves the itinerary and writes it to a BizTalk context property in the inbound message after receipt during the Send Receive process cycle.”

The above definitions are taken directly from MSDN…

There is no need to further explain what this component is used for as the above definitions handle this nicely…

Question: How does this thingy-magiggy work???

Answer:Under the hood, the ESB ItineraryCache is a pipeline component that caches the Itinerary into a cache object defined the the Enterprise Library 4.1 caching application block mechanism upon sending the message, and retrieves the itinerary from the cache upon receiving the the message. Thus this component functions differently upon if the component is executed from a Send pipeline versus a Receive Pipeline.

The Default Mechanism:

By default this caching is done in memory and only caches your itinerary for 5 minutes. The Itinerary is stored and retrieved through the Cache object collection using the CorrelationContextPropertyName property which is set on the pipeline component property sheet. Again, by default the value for this property is the TransmitWorkID context property which can be found as a BizTalk system property.

What is interesting to note here, is that for every itinerary that is transmitted or received, this property must be promoted in order to write or read to the caching collection; along with the fact that the value for this property must be unique within a 5 minute time span, otherwise an non-unique key argument exception will be thrown. Also by default, this property is only promoted by BizTalk when the message is received from a 2-way Receive Port. This property is usually used in conjunction with the IsRequestResponse , the IsSolictResponse, the WasSolicitResponse , and the RouteDirectToTP BizTalk system properties to help correlate 2-way synchronous responses within BizTalk 2 way adapters, orchestrations, and other 2 way patterns. Thus, if you are not using a 2 way receive port, 2-way Receive Adapter, or Correlated 2 way design pattern, these properties, including the TransmitWorkID will not be promoted. This means that by default you won’t be able to use the itinerary caching component.

Another note to take interest in is that when using this caching component, upon transmission (sending) of the message, the component will only write the itinerary into the cache if a few conditions are met:

  1. The ESB determines that the direction of the message flow is a true “SendTransmit”. How the ESB Determines this condition is using two branches. The first branch checks to see if the IsRequestResponse property is true. If so, the ESB continues to check for conditions that do not satisfy the Receive Transmit (the sending side of a 2 way receive port), or Receive Inbound (the receiving side of the 2-way receive port). The Receiving Transmit conditions are simply checked against the Send Port Name being promoted and WasSolicitResponse containing any value; whereas the Receiving Inbound conditions are checked against the Receive Port Name being promoted. If these cases are not true, ESB checks for the IsSolicitResponse = true , which determines that the message direction is a true “SendTransmit”. The second branch checks for the case of IsRequestResponse = false. If the Receive Port Name, and Send Port Names are not promoted, nor is the WasSolicitResponse = true, then the ESB checks for the Send Port ID property to be promoted, in which signals the message direction to be a true “SendTransmit”
  2. BizTalk has properly promoted the BTS.IsRequestResponse or the ESB Itinerary.IsRequestResponse properties to true. This is done again by using a 2 -way Receive Port, or using an Itinerary, Itinerary Routing shape, Off Ramp or Off Ramp extender and setting its IsRequestResponse property to “ true”, and in some cases, all of the shapes in question must have these properties to “true”.

  3. When writing the Itinerary to the cache, the CorrelationContextPropertyName value exists.

  4. When writing the Itinerary to the cache, a duplicate does not already exist for the CorrelationContextPropertyName value.

Upon receiving the message, the same type of checks are also evaluated when trying to retrieve the itinerary from the cache:

  1. When reading from the cache, the CorrelationContextPropertyName value must exist.

  2. The ESB determines that the direction of the message flow is a true “SendInbound”. How the ESB Determines this condition is also using two branches. The first branch is exactly like the “SendTransmit” logic, the only exception being ESB does NOT check for the IsSolicitResponse = true; however does check to see if the Send Port Name is promoted, which determines that the message direction is a true “SendInbound”. The second branch is also similar to the “SendTransmit” with the only exception being the if the Send Port Name is promoted, the message direction is considered a true “SendInbound” .

If you don’t want to be subjected to using 2-way receive ports, or you want to use this Caching mechanism outside the scopes of a 2-way Send port (i.e. a 2-way Asynchronous design pattern), you can use a custom CorrelationContextPropertyName , and Namespace setting, and override the default IsRequestResponse , WasSolicitResponse , and optionally RouteDirectToTP (for sending back to the original caller), system properties. If you’ve read above, you should have a basic overstanding of how the Itinerary Cache works, which should allow you to be dangerous in how to model 2 way Itineraries. See a future post on this…

Extending the Default Caching Mechanism:

Extending the default Itinerary Caching component is as simple as changing the default CorrelationContextPropertyName , or changing the Timeout property, Creating a custom Itinerary Caching component, or even the default Caching manager.

If you don’t want to be subjected to using 2-way receive ports, or you want to use this Caching mechanism outside the scopes of a 2-way Send port (i.e. a 2-way Asynchronous design pattern), you can use a custom CorrelationContextPropertyName , and Namespace setting, and override the default IsRequestResponse , WasSolicitResponse , and optionally RouteDirectToTP (for sending back to the original caller), system properties. If you’ve read above, you should have a basic overstanding of how the Itinerary Cache works, which should allow you to be dangerous in how to model 2 way Itineraries. See a future post on this…

Routing 2-way Synchronous response to endpoints other than the initiator

Routing 2-way Synchronous response to endpoints other than the initiator

Recently, in our implementation of an ESB 2.0 BizTalk 2009 solution, a requirement popped up where an endpoint initiates a request to a synchronous system, and the system responds back with a response. In typical development practices, this is referred to a request/response or client/server pattern. You may say to yourself, “big deal, this is easy…” In a normal solution, the response is routed back to the initiator of the request. Lo and behold, we came across a scenario, where the response needs to be routed to other endpoints based on fairly complex rules and processes; not the original caller (initiator), hence the purpose of this blog entry.

As a BizTalk Developer, you say the above is not a problem. Why? Because BizTalk can handle designs like this with ease, using orchestrations, static send ports with unique filter expressions, and even orchestrations with dynamic send ports. You can actually put the complex logic, rules and processes inside custom components, or the Business Rules Engine (BRE) within orchestrations or even pipeline components. However if we’re staying true to the Agile game, and we want to build a architecturally sound ESB, using the normal BizTalk approach doesn’t fit the bill, in other words, it won’t work. The reasons why are simple, we either loose Agility, gain invisibility, create a mystery black box with custom code, or have increasingly complex algorithms which are prone to break and miss the agile mark altogether. The goal here is to think about BizTalk 2009 and the ESB 2.0 toolkit as a set of capabilities and then model the capabilities to generate the result you want.

Question: So now what capabilities do we need?

Answer: We want the ability to design steps or process flow which accepts a message from an initiator, and then based off of some rules, dynamically determine the 2 way service, retrieve the response and through more rules dynamically send the response to another endpoint who is not the initiator.

Question: So which capabilities match BizTalk and ESB?

Answer: The capabilities to design steps and process flows are the Itineraries pattern of ESB. The BizTalk Business Rules Engine incorporates the complex logic. The ESB Resolvers assist to resolve logic, and endpoint addresses, such as the 2 way service to invoke, and the resulting endpoint to send the responses to. In addition to the resolvers, BizTalk provides WCF Adapters to send and receive the request/response and results.

Question: So how do we do this?

Answer: You model an itinerary in BizTalk 2009’s ESB 2.0 using the Itinerary designer that accepts a message from a caller (initiator), and then sends the request to a 2-way Synchronous Endpoint, which then blocks (correlates automatically for the response) and then sends the Response to a completely different endpoint based off of a Business rule.

Question: Is this easy?

Answer: Yep Follow these high level steps:

  1. Create an Itinerary using the ESB Itinerary Designer.

  2. Configure the Itinerary to use a 2-way Receive Port, even though you will use a 1-way receive port in production.

  3. Configure the Itinerary to be a Request/Response Itinerary, which is to say verify the IsRequestResponse = true. (See the Itinerary Cache Post for more info on this… https://dgoins.wordpress.com/2010/02/22/overstanding-the-esb-itinerary-cache-2/)

  4. Model the itinerary with with the call the the synchronous request/response endpoint.

  5. Within your steps, use the BRE Resolver to determine maps, and endpoint addresses for the configuration of which synchronous endpoint to send the request to.

  6. Optionally: Use the Service Broker shape to route to different endpoints based off of promoted properties from the response.

  7. Lastly, use a Business Rule Resolver to dynamically determine the resulting endpoint configurations.

Below is an example of an Itinerary which uses Business Rules to invoke a Synchronous endpoint and routes the results to another endpoint which is not the initiator.

Explanation of Itinerary:

The above image can be read following the directions of the arrows, starting with the upper Left shape named: ReceiveMsg . This first shape signifies an ESB OnRamp, which equates to a BizTalk Physical receive port.

The next shape: MapToCanonical represents an ESB Messaging Step. Messaging steps are processes or components that are destined to execute inside of pipelines. These pipelines are configured with ESB based pipeline components such as the ESB Dispathcher, which understand the Itinerary step mechanism to execute ESB Itinerary steps. In the above example, the MapToCanonical step uses a Transform based ESB Step process to execute a BizTalk transformation (Map) to convert the message received from the OnRamp into a canonical message format. The map which executes is determined by the ESB Resolver: SetMapToCanonical . This resolver utilizes the BRE Resolver to execute and evaluate complex logic using the BizTalk Business Rules Engine (BRE) to choose the correct map for transformation.

The next step: RouteToEndPoint is another ESB messaging step, which utilizes the ESB Routing process to promote properties and publish the message to the BizTalk Message box. This step is configured to use the BRE Resolver named: GetURI . This resolver executes business logic and evaluate rules to determine the URI address, and Send adapter to send the request to.

The next step: PushToMsgBox, is an off ramp extender shape which gathers more promoted property information from the actual ESB OffRamp: SendToEndPoint (BizTalk Physical Send Port). Here’s an interesting point to note, remember that the ESB Itinerary pattern is just a model to design steps as in the order of execution, not the actual process such as an orchestration. As we define our steps, BizTalk needs to know where these ordered steps should execute. In other words, when we use “Messaging Steps” these obviously execute inside Messaging components of BizTalk, hence pipelines stages. However, for BizTalk we have two sides of the messaging system. BizTalk has a messaging stack before saving to the Message Box (Receive Pipelines), and a stack after the Message Box (Send Pipeline). In the design above, the PushToMsgBox off ramp extender is used to signify all steps after this will execute in the Send Handler (Send pipeline stages).

The next step after the off ramp extender is the MapToEndPoint step. This step, again is a messaging step which uses the BRE Resolver named: SetMapToEndPoint , will be executed after the message is published to the BizTalk Message box, and inside the send pipeline associated with the send port configured through Off Ramp: SendToEndPoint .

The next step is the SendToEndPoint ESB Off Ramp. This Off Ramp is configured to use a 2-way Solicit-Response dynamic send port. From a BizTalk perspective, the 2-way dynamic send port is configured to use a send pipeline which contains the ESB Dispatcher pipeline component, and the ESB Itinerary Cache pipeline component. The receive pipeline is configured to use the ESB Itinerary Cache, Xml Disassembler, and the ESB Dispatcher components respectively. The 2-way send port is also configured with the 4 basic ESB promoted properties within the Filter expression. Screen shots of the various properties and values are provided below.

The next step is MapResponseToCanonical . Notice here that the messaging step is set to run in the Receive Handler (Receive Pipeline) of the SendToEndPoint off ramp. This means that this step runs on the receiving side of the 2-way dynamic send port. This step is configured to use the ESB Transformation service, and the BRE Resolver to again determine which map to use for transformation. This step transforms the reponse to a canonical format to eventually publish back to the Message Box.

The next step is RouteResponseToEndPoint, just like step before, this step also is configured to execute in the Receive Handler of the SendToEndPoint off ramp. Which also means it will execute on the receiving side of the 2-way dynamic send port. This step is also configured to use the ESB Routing service and again the BRE Resolver to determine the Endpoint URI and adapter to use to send the final response.

The next step is PushResponseToMsgBox. This step is an off ramp extender which signifies that the remaining steps will be executed after the message is published to the Message Box, along with any other special properties that need to be promoted.

The next step is MapResponseToEndPoint, this step is a messaging step which again uses the ESB Routing Service and the BRE Resolver to determine the Uri address and BizTalk Send adapter settings to use for sending the response.

The last step is SendResponseToEndPoint, this is the Off Ramp which points to a simple Dynamic Send port for actually sending the response from BizTalk.