Format of BizTalk 2004 assemblies: How do artifacts get compiled to .NET assemblies

Today, we explore some undocumented (and therefore not supported) internal parts of BizTalk 2004. When a BizTalk project is compiled, artifacts like Messages, Orchestrations, Pipelines, Maps or Schemas (to mention only a few) are compiled into a .NET assembly. In the assembly, one type represents one artifact. These types are most of the time classes and they inherit from a base class that best represent the kind of BizTalk artifact's behavior. For instance, maps inherit from Microsoft.XLANGs.BaseTypes.TransformBase while schemas inherit from Microsoft.XLANGs.BaseTypes.SchemaBase. These types are defined in Microsoft.XLANGs.BaseTypes.dll, available in <BTS Installation Directory> and many classes in this assembly are officially not supported as explained by this page  (look at the bottom of the page). The following table contains the most common artifacts and their base class. Notice that Orchestrations inherit from a special class contained in Microsoft.XLANGs.BizTalk.Engine.dll.

Artifact Base Type
Map Microsoft.XLANGs.BaseTypes.TransformBase
Schema Microsoft.XLANGs.BaseTypes.SchemaBase
Pipeline Microsoft.XLANGs.BaseTypes.PipelineBase
Orchestration Microsoft.XLANGs.BaseTypes.BTXEngine.BTXService

I mentioned previously that a BizTalk artifact compiled to one type into the .NET assembly. The mapping one artifact to one .NET type is actually not true for orchestrations: a few other supporting types are added to the assembly. As far as type visibility is concerned, everything except Orchestration is defined as public sealed class. Orchestrations are compiled as internal sealed classes.

Many other things go into the .NET assemblies. For instance, messages passed as parameters to orchestrations are compiled as public sealed classes inheriting from Microsoft.BizTalk.XLANGs.BTXEngine.BTXMessage. Each property defined using a property schema gets compiled to a public sealed class inheriting from Microsoft.XLANGs.BaseTypes.MessageDataPropertyBase.

At assembly deployment time, BizTalk extracts metadata about all available types and saves the results to the BizTalk management database. This is a performance optimization: reflection is slow and forces to load the assembly into the application domain. By saving artifact's critical information in a database, BizTalk avoids loading assemblies and performing reflection on them. Since the current version of the .NET framework assemblies cannot be unloaded without tearing down the whole application domain, it can lead to substantial memory savings.

At runtime, BizTalk artifacts can be roughly divided into two groups: the ones that needs to be loaded into memory to run and the one that do not need to. Some artifacts like Pipelines can be run without even loading their assembly into memory. The metadata collected at deployment time contains all the information required. In this case the configuration data is used instead. This is one of the reasons why simply replacing the assembly on the file system does not force BizTalk to take changes into account. The assembly must be deployed again to update the management database.

Orchestrations belong to the second group: their assembly needs to be loaded (and in fact executed) at runtime. The assembly actually contains the code implementing the XLANG schedule. It is now easy to understand that to apply changes to an orchestration; one has re-deploy the assembly (to update the management database) and to stop and restart the BizTalk host (to unload the assembly from the application domain).

The story above is a simplification of the actual process. There are other factors coming into play like side by side versions of artifacts that I have not taken into account here. However, the previous description is accurate enough to understand what happens internally.

It is beyond the scope of this blog to discuss how orchestrations or properties get compiled to .NET assemblies. However, some simpler artifacts can be described precisely: Maps, Pipelines and Schemas. Tomorrow, I'll describe precisely how maps get compiled into assemblies.