Interesting tech stuff I come across day-to-day. Mainly around Biztalk and .NET 3.0

please ignore - posted for Technorati claim

Thursday, June 21, 2007

Technorati Profile




Adding Custom HTTP Headers to messages send via HTTP Adapter.

Wednesday, June 06, 2007

Download Full sample code here

There will often be times we need to add some custom HTTP Headers to our outgoing message. The common one we come across is SOAPAction, if you need to communicate with the web services just with HTTP adapter (not using SOAP Adapter).

BizTalk server gives us a context property called "UserHttpHeader" as part of the HTTP adapter, which can be used to set custom HTTP headers.

The below Orchestration shows an example, how you can take advantage of "UserHttpHeader" property.

image

The code inside the "Message Assignment" shape is shown below:

MSG_AUTHOR_OUT = MSG_AUTHOR_IN;
MSG_AUTHOR_OUT(*) = MSG_AUTHOR_IN(*);
MSG_AUTHOR_OUT(HTTP.UserHttpHeaders) = "userName: Saravana\r\npassword: hola";

Important things to note:

  1. You can add multiple headers (ex: userName, password) in a single line as shown in the sample above.
  2. "\r\n" is used to separate multiple headers.
  3. ": " is used to separate header and value, you must specify a SPACE after colon.

The content of the output file is shown below

POST /HTTPReceiver/Default.aspx HTTP/1.1
Connection: Keep-Alive
Content-Length: 312
Content-Type: text/xml; charset=utf-16
Expect: 100-continue
Host: localhost:3131
User-Agent: Microsoft (R) BizTalk (R) Server 2006 3.0.1.0
userName: Saravana
password: hola

<?xml version="1.0" encoding="utf-16"?><<stripped content for clarity>>

I used an orchestration sample to demonstrate how you can set UserHttpHeader context property. But like any other BizTalk context property you can set this property in different places like within custom adapter, custom pipeline etc.

Download Full sample code here

Nandri!

Saravana




Implement Caching for your BizTalk applications using "static" classes and methods.

Monday, June 04, 2007

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>();
                lock (_authorIds)
                {
                    _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");
                }
            }
            else
            {
                Debug.WriteLine("Cache list is pre-populated. Value is going to be taken from the cache.");
            }
            string authName = _authorIds[authorId];
            if (authName != string.Empty)
                return authName;
            else
                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:

Service Description
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.

Orchestration

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:

image

For subsequent messages (I posted 4), DebugView showed the following output:

image

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.

Download the full sample here.

Nandri!

Saravana




Determine whether the BizTalk assembly is Debug or Release build at runtime.

Saturday, June 02, 2007

Recently someone raised this question in the newsgroup, they wanted to branch inside the orchestration based on the build of the assembly itself. Whenever an assembly is build with "Debug" mode, some System.Diagnostics.DebuggableAttributes are added to the assembly. One such attribute is "IsJITTrackingEnabled", which will track information during code generation (MSIL) for the debugger.

So, we can use the simple technique of reflection to determine whether the assembly is build against "Debug" or "Release" mode by the presence or absence of IsJITTrackingEnabled attribute. The below method does exactly the same:

public static bool IsDebugBuild(System.Reflection.Assembly assembly)
{
object[] attributes = assembly.GetCustomAttributes(typeof(DebuggableAttribute), false);

if (attributes.Length == 0)
return false;//No debug attibutes, so release build

foreach (Attribute attr in attributes)
{
if (attr is DebuggableAttribute)
{
DebuggableAttribute d = attr as DebuggableAttribute;
if (d.IsJITTrackingEnabled == true) //this flag is set only for debug builds
return true; //Debug
else
return false; //Release
}
}
throw new Exception("Cannot determine the build type");
}

Place the above code in an utility class (external assembly), build and GAC it. Inside your Orchestration, reference the assembly, define a variable (ex: assm) of type "System.Reflection.Assembly" and call the method IsDebugBuild as shown below inside your Expression shape

assm = System.Reflection.Assembly.GetExecutingAssembly();
System.Diagnostics.Debug.WriteLine(Utility.DetermineDebugOrRelease.IsDebugBuild(assm));

Place the above code in an utility class (external assembly), build and GAC it. Inside your Orchestration, reference the assembly, define a variable (ex: assm) of type "System.Reflection.Assembly" and call the method IsDebugBuild as shown below inside your Expression shape

assm = System.Reflection.Assembly.GetExecutingAssembly();
System.Diagnostics.Debug.WriteLine(Utility.DetermineDebugOrRelease.IsDebugBuild(assm));

NOTE: This example is just to address someone's question. You should try NOT to use this type of code in production. Because reflection is an expensive process and it doesn't really suits well for high throughput BizTalk applications.

Nandri!
Saravana

Labels: