UPDATED: 24th August 2007, to reflect Richard Seroter's comment
There is no necessity to explain the importance of caching in any server based developments like BizTalk, ASP .NET etc. You need to plan early in your development cycle to cache resources in order to make most out of your limited server resources.
In BizTalk applications, it's quite common to lookup a data store to pickup a value, at different stages like custom Adapters, Pipelines, Orchestration, etc. The data store could be a custom SQL database/table, a XML File, Active directory etc etc. Whatever the data store is, if you are doing the lookup for every message you process without any caching, its going to be an expensive and useless operation.
Due to the nature of BizTalk architecture and behavior of .NET run-time, its very easy to implement a caching logic just with a static class and a static method as shown below:
public static class CacheHelper
private static Dictionary<string, string> _authorIds = null;
public static string GetAuthorName(string authorId)
if (_authorIds == null)
Debug.WriteLine("Cache is empty. So populating the cache…");
_authorIds = new Dictionary<string, string>();
_authorIds.Add("2FC0CF1D-E107", "Matthew Johnstone");
_authorIds.Add("71F5C860-80FA", "Carl Reynolds");
_authorIds.Add("158FF294-1A89", "Robert Perkins");
_authorIds.Add("A71AE681-9C39", "Michael Killey");
_authorIds.Add("58794661-A9A3", "Saravana Kumar");
Debug.WriteLine("Cache list is pre-populated. Value is going to be taken from the cache.");
string authName = _authorIds[authorId];
if (authName != string.Empty)
throw new Exception("Author cannot be found with id :" + authorId);
In .NET static variables are maintained per Common Language Runtime (CLR) "AppDomain". We can just exploit this behavior of .NET for our caching needs.
Inside the BizTalk server host instances, several subservices will be running. The exact services can be found in the adm_HostInstance_SubServices table in the BizTalk Server Management database. The services are listed here for reference:
|Caching||Used internally by BizTalk Server to cache configuration information for the other services|
|Endpoint Manager||Responsible for hosting receive and send ports including adapters and pipelines|
|Tracking||Responsible for moving data out of the MessageBox database and into the BAM or Tracking databases as appropriate|
|XLANG/s||Host engine for BizTalk Server orchestrations|
|MSMQT||MSMQT adapter service; serves as a replacement for the MSMQ protocol when interacting with BizTalk Server|
The BizTalk host instance simply acts as a container to host these other services. When the service is started, each of these subservices is started as well. They handle all of the processing related to the messaging and orchestration engines in BizTalk Server. For isolated hosts, the Endpoint Manager is the only service that is loaded into the process. Isolated hosts are only intended to be used for hosting adapters that send and/or receive messages.
So, inside the BizTalk host instance by default there will be one .NET "AppDomain" created per each BizTalk SubService (EPM, XLANG, etc). Majority of our custom code will be running under the "AppDomains" either created for EPM (if you are doing any messaging related stuff, example custom pipeline components and any assemblies you reference) or XLANG (any custom orchestration and any assemblies you reference). Both the "AppDomains" will be hosted inside the BizTalk host instance.
As I mentioned earlier, in .NET static variables are maintained per Common Language Runtime (CLR) "AppDomain". Any static data you hold lives inside the "AppDomain" for the life time of the "AppDomain", in BizTalk term that means from the time BizTalk Host Instance is started, corresponding DLL's (pipeline components, pipelines, orchestrations, in general any custom assembly like schemas, maps, helper classes) are loaded (assemblies get loaded into "AppDomain" on demand) into the "AppDomains" (EPM, XLANG, etc) to the time BizTalk host instance is restarted.
We can utilize this behavior of .NET run-time, to create a pattern to cache values, which doesn't change very often. Lets see the behavior with an example.
Here is an example using Orchestration:
In the above code snippet (showed earlier), I just added few Name-Value pair items to "authorsIds" collection, in real world scenarios we might need to populate them from a data store like SQL database. If we are doing that database lookup for every message, then its going to be unnecessary roundtrip's to the database and wastage of server resource.
This utility class can now be used in any of your custom BizTalk solution like Adapters, Pipelines, Orchestrations etc. The following Orchestration shows its usage.
The message assignment shape got the following lines of code.
MSG_AUTHOR_OUT = MSG_AUTHOR_IN;
MSG_AUTHOR_OUT.Name = Utility.CacheHelper.GetAuthorName(MSG_AUTHOR_IN.Id);
When I Build, Deploy and run the sample, for the first message the DebugView showed the following output:
For subsequent messages (I posted 4), DebugView showed the following output:
You can make sure the cache is repopulating by restarting the BizTalk host instance (NT Service).
NOTE: If you are using isolated adapters like HTTP/SOAP the data will be cached under the IIS worker process, so to reset the cache you need to reset IIS.
This technique is simple to implement and easy to use. If you want more advanced caching like cache expiration, dependency etc then you can consider using Enterprise Library caching application block.