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.

64 Bit ESB/BizTalk Lessons Learned

As some of you are well aware of. We at Tellago (http://www.tellago.com) are implementing a major ESB 2.0/BizTalk 2009 (64 bit) solution. This blog posts servers as a reminder of the configurations, issues, and *gotchas* we have identified thus far. So this list will be a living list J

  1. Beware of the applications that are really 32bit running on a 64bit host. Use the Task Manager to check to see if it’s a 32bit or 64bit process
    1. For example when configuring behaviors or anything that is done in a configuration file for any normal WCF Service using the SvcUtility (which is a 32bit process), the settings need to be applied in the 32bit configuration file to see it, as well as in the 64bit configuration file locations. *Twice as nice* – yeah
    2. Locations to be aware of for the Machine Config:
      1. %windows%\Microsoft.Net\v.x.x\Framework64\Config
      2. %windows%\Microsoft.Net\v.x.x\Framework\Config
    3. Another example is when configuring a WCF Custom adapter using the BizTalk Admin Console (32bit process) reads the Machine configuration from the 32 bit location as outlined above instead of the 64 bit locaiton, however the runtime reads it from the 64 bit location *gotcha*!!! Thus any behaviors or custom bindings needs to be configured in both the 32bit and 64bit machine configuration files…. !!!
  2. When using The BRE with classes that use static methods the Registry location has changed for 64 bit it’s now in the Wow6432Node… however the StaticSupport value is a DWORD(32 bit) not 64bit… *Gotcha*!!!
    1. Static Support:
      1. HKLM\Software\Wow6432Node\Microsoft\BusinessRules\3.0\
      2. Value to set: StaticSupport DWORD (32bit) 1
  3. When configuring WCF Custom Isolated URL’s in IIS 7.0 64bit: Don’t copy paste Urls, manually type them in. *gotcha*!!!
  4. For BizTalk configuration, trace sources, SVC traces and etc… change the BizTalk 64bit exe configuration file.
  5. When running WCF-CustomIsolated, and IIS 7.0 applications, verify that the assemblies running in this space are not limited to 32bit hosts, if so, run the application pool as a 32 bit host only mode.
  6. Beware of using the BizTalkExplorerOM classes in components, by default this library does not support 64 bit. To use any of this library, you must run it in a 32 bit Default Host, or recompile the component that uses this library with the 32bit compile option in VS.NET; just make sure you change it from the default *any* compile option. There is an MSDN article on this I’ll post it later…
  7. MIME Decoder only supports 32 bit. Thus you’ll need to run this in the 32bit Host instance
  8. SQL Adapter (Not WCF-SQL Adapter with the WCF LOB Adapter Kit) only supports 32bit Host Instance
  9. Beware of using Dynamic Send Ports with a 32 bit default host. All dynamically configured adapters will use the Default Host Instance for that 32bit Default Host. There is no way to dynamically configure which Host a dynamic adapter will use.

64Bit – WCF Custom Isolated – REST – “504” response

Tonight my fellow Tellago-ans, and I ran into a issue using the WCF-CustomIsolated Adapter on Windows Server 2008 64bit.

We were trying to use the .Net 3.5 bindings/REST styled architecture to support HTTPv1.1 Posts into BizTalk using the WCF CustomIsolated Adapter. In our lab and development environments, process worked like a charm. We used HTTP Fiddler to test the data and message flow. Here’s an example of what I mean:

In the above screen shot, we have configured a WCF-CustomIsolated adapter to use the .Net 3.5 WebHTTPBinding. (Instructions on how to do this can be found in Adrian’s blog). When using Fiddler, we can easily make posts into the BizTalk Server:

And our response we would receive would be something similar to this:

 

However upon moving our solution to a 64bit BizTalk Server running on IIS 7.0 (64bit Mode), the HTTP Post no longer worked. We started receiving “504” gateway issues.

Now oddly enough these servers were behind a firewall; we did need VPN accounts and software to access these servers; and also to mention, to get any internet access we went through a web proxy. This would lead any logically thinking person to believe the problem lie in one of these culprits: Firewall, VPN, or proxy…

Not so fast says the turtle!!!

Well, we started looking more into this and turned on WCF Tracing and looking into the Event Viewer and saw that we were receiving a weird WCF error. The error was:

The adapter “WCF-CustomIsolated” raised an error message. Details “System.XmlXmlException: Unexpected end of file.

At System.Xml.EncodingStreamWrapper.ProcessBuffer(Byte[] buffer, Int32 offset, Int32 count, Encoding encoding)…

(and on and on…)

 

We did not have a malformed message, after all it was Http Fiddler and we were just typing in a dummy xml message like “<Blah/>” and the WCF Adapter was failing horribly on the 64bit machine, where as the 32bit machine ran like charm… We started to think maybe it was an encoding issue, or something…

So Here’s the WTF for the day!!!

It turns out the issue lie in the fact that the WebHttpBinding element by default utilizes the transferMode set to Buffered.

Apparently there is an issue when trying to use this setting on a win64 bit OS, with IIS 7.0 in 64bit mode, with BizTalk WCF-CustomIsolated adapters… Our fix:

You guessed it: set the transferMode property to Streamed issue resolved.

What Happened to the ESB MSMQ Adapter Provider?

In our current, project we built an itinerary that utilized the Business Rules Engine (BRE) to set an endpoint to the MSMQ Adapter. Lo and behold, there was no MSMQ Adapter provider, until now, Below is our source code for cheating the Adapter Provider framework for building a custom MSMQ Adapter Provider. The code was simple and to the point. No explanation necessary…

Source Code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.ESB.Adapter;

using Microsoft.BizTalk.Message.Interop;

 

 

namespace Tellago.ESB.AdapterProviders

{

/// <summary>

/// Ths class implements IAdapterProvider for setting the context properties of

/// the BTS MSMQ adapter. Loaded by the AdapterMgr class

/// </summary>

public class MSMQAdapterProvider : BaseAdapterProvider

{

public override string AdapterName

{

get { return “MSMQ”; }

}

 

public override void SetEndpoint(Dictionary<string, string> ResolverDictionary, IBaseMessageContext msg)

{

base.SetEndpoint(ResolverDictionary, msg);

}

 

public override string AdapterContextPropertyNamespace

{

get

{

return “http://schemas.microsoft.com/BizTalk/2003/msmq-properties&#8221;;

}

}

 

protected override void SetEndpointContextProperties(IBaseMessageContext pipelineContext, string endpointConfig)

{

base.SetEndpointContextProperties(pipelineContext, endpointConfig);

 

string[] properties = endpointConfig.Split(new char[] { ‘&’ }, StringSplitOptions.RemoveEmptyEntries);

 

foreach (string property in properties)

{

string[] data = property.Split(new char[] { ‘=’ }, StringSplitOptions.RemoveEmptyEntries);

string key = data[0];

string value = data.Length < 2 ? “” : data[1];

 

pipelineContext.Write(key, this.AdapterContextPropertyNamespace, value);

}

}

 

public override void SetEndpoint(Dictionary<string, string> ResolverDictionary, Microsoft.XLANGs.BaseTypes.XLANGMessage message)

{

base.SetEndpoint(ResolverDictionary, message);

}

 

protected override void SetEndpointContextProperties(Microsoft.XLANGs.BaseTypes.XLANGMessage message, string endpointConfig)

{

base.SetEndpointContextProperties(message, endpointConfig);

}

 

protected override void SetContextProperties(IBaseMessageContext pipelineContext, Dictionary<string, string> ResolverDictionary)

{

base.SetContextProperties(pipelineContext, ResolverDictionary);

}

 

protected override void SetContextProperties(Microsoft.XLANGs.BaseTypes.XLANGMessage message, Dictionary<string, string> ResolverDictionary)

{

base.SetContextProperties(message, ResolverDictionary);

}

}

}

Steps to use:

1. Rebuild and GAC this project

2. Open the ESB.Config file from the install folder

Add the following line in the Adapter Providers section:

    <adapterProvider name=”MSMQ” type=”Tellago.ESB.AdapterProviders.MSMQAdapterProvider, Tellago.ESB.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c0eafbe4dc54c287″ moniker=”msmq” />

    

Happy ESBng!!!