
Understanding types in BizTalk
All good technology makes the complex look simple. BizTalk is no exception, but beneath this simple façade lie some fairly complex constructs. This section gets very deep into some complex parts of BizTalk and the .NET framework. Do not worry if you don't understand it, and feel free to skip over it, but be sure to remember where it is for when you need this knowledge.
The preceding compiled projects are actually .NET assemblies that will be used by the BizTalk runtime to execute our solution. All BizTalk artifacts become .NET types when they are compiled. Understanding types in BizTalk is slightly tricky at times and we'll walk through it now.
In most programming languages, types are the structures we work with to organize our code. BizTalk bridges a gap between messaging, which is often XML and .NET. This means that BizTalk has both messaging types and .NET types. Messaging types are for XML messages, but everything is a .NET type. If we look at the properties of any BizTalk artifact in Visual Studio we can see that they all have a section for Namespace and TypeName. This is a core concept of .NET. Namespaces are used to organize classes and types. A good example would be System.Net
which is the collection of classes and types having to do with networking in the .NET framework. In this namespace, there is a class identified as System.Net.WebRequest
; WebRequest
is the actual class and it is in the namespace System.Net
. Because our BizTalk artifacts are all compiled into .NET types for use by the BizTalk runtime, they must all be organized into namespaces and types. The best way to do this is to set the default namespace in the project properties in Visual Studio. Each project that we outlined previously should have its default namespace set before we start adding artifacts to them.
The typical naming convention for project namespaces would be as follows:
[Company abbreviation].[Solution].[Project]
An example external schemas default namespace for a company called Performance Racing Parts creating an order processing solution would be:
PRP.OrderProcessing.ExternalSchemas
In very large organizations, this can be expanded to include a division if necessary.
[Company abbreviation].[Division].[Solution].[Project]
The project portion of the namespace should match the name we give the project within the solution and helps us to organize our artifacts better. Each artifact will then have a fully qualified name organized by namespace. To complete our example a schema for a sales order in our external schemas project would have a .NET name (namespace+type) of PRP.OrderProcessing.ExternalSchemas.SalesOrder
.
Message types
XSD schemas in BizTalk have .NET name type like we covered previously, but XML messages that conform to those schemas also have an XML message type. In XML, it is common to identify documents by their fully qualified root element name; this includes the namespace and the element name. Unfortunately in this case, the worlds of XML and .NET have collided and namespace is an overloaded term. In the following XML, we can see an example of an XML namespace: http://somecompany.net
.
<order xmlns="http://somecompany.net"> <number>1234</number> </order>
The message type for this XML document would be http://somecompany.net#order
and this is how BizTalk will identify the message and match it to a specific schema. It is this dual identity role that can be tricky for a lot of developers new to BizTalk.
For non-XML messages, as far as the messaging infrastructure is concerned, they are generally untyped. This means we cannot use data from within their content for routing or use maps on them, but we do still have context and internally BizTalk does use .NET types to represent them. As these types are internal to BizTalk, they are generally not too visible to developers.
Types in contexts
In BizTalk, there are not just different types of types there are also different types in different contexts. All messages in BizTalk's messaging engine, including pipeline components, are represented as an instance of the interface Microsoft.BizTalk.Message.Interop.IBaseMessage
. Once in an orchestration a message is represented as an instance of Microsoft.XLANGs.BaseTypes.XLANGMessage
and can be sent to or from a user component as such. Often this would be in a helper class. Interestingly enough, these types cannot be converted between each other, nor can they be casted. You'll generally use IBaseMessage
in pipeline components and XLANGMessage
exclusively in orchestrations.
If this is a little confusing at first you're not alone, but trust me, it makes sense once you stop fighting it. Look at it this way: a message arrives in BizTalk, goes through a pipeline (and its components) and a map then goes to the message box. It was represented by IBaseMessage
this entire journey and its journey is over. Even if you have an orchestration that will receive this message, it will receive it as XLANGMessage
and in a fresh receive, completely disconnected from the first operation (the adapter, pipeline, and map). In our minds as developers, this all looks like one flow and that is the catch with BizTalk. It is not one flow, it is two, and they are completely decoupled. Delivery to the message and then to the orchestration engine are in fact two distinct operations.
To make things a little more complicated, any message in an orchestration can also be declared as an instance of System.Xml.XmlDocument
. It is not so much that these classes are all related per se, but they have both practical and historic reasons for this arrangement. Historically this is because the original versions of BizTalk used the DOM extensively to pass around XML documents; as a result the use of the XmlDocument
class, which is the .NET DOM
object, was included to make it easier for developers and solutions to be ported to newer versions of BizTalk. This has been a decision that has caused much confusion over the years. Another reason is that it allows you a simple way to deal with non-XML messages in orchestrations; you can specify their type as XmlDocument
and handle just about any type of message, even binary. That said, if you have a non-XML message and try to use any of the members of XmlDocument
on it, you will receive an exception from the orchestration engine at runtime. XmlDocument
is very dangerous to use in orchestration and should be avoided at all costs. Its use was common in older versions of BizTalk, but should not be repeated. Further, XmlDocument
is actually not what it at first appears. Although the language of the orchestration engine appears to be C# it is in fact a different language X#; the XLANGs language. XmlDocument
in the context of X# is actually a wrapper around the real XmlDocument
class from the System.Xml
namespace which, even more inexplicably, is not serializable.
These different interfaces (or interface and classes) allow different types of interactions with messages in their own contexts which can sometimes be challenging until you understand the lay of the land so to speak. All will allow you to manipulate message bodies, but again, care must be taken here so as not to load the entire message body into memory at once, which is the real downfall of XmlDocument
. Recall our coverage of streaming.
To sum it up, in these contexts, messages are of these types:
Messaging Engine: IBaseMessage
Orchestration: XLANGMessage
or XmlDocument
Type resolution
Even in a messaging-only scenario where orchestration is not involved, BizTalk does a sort of two-phase type resolution. The first is to determine the message type via message inspection, which is performed by XML and flat file pipelines. This is where the namespace and root element name will be used to resolve the message type. From here BizTalk uses this message type to retrieve the schema information from a .NET assembly that actually contains the schema. This assembly is deployed with the MSI you install, or from Visual Studio, in the case of a workstation. This is an automatic resolution based on a BizTalk global catalog of namespace and root element name for all schemas deployed to BizTalk.
A conflict can and normally will occur if you deploy multiple schemas containing the same namespace and root element combination to BizTalk. This happens when one of these messages is received and run through a pipeline like the XmlDisassembler
(that is, something that inspects the message to determine its type). The error will be very clear, normally including "Multiple schemas match the message type". This makes sense, because you have done something naughty and short circuited BizTalk's message type resolution mechanism.
A final note is in order here. The Pass Thru pipelines, as their name implies, don't inspect or modify messages in any way. They are almost like a null pipeline that simply lets a message flow unaltered through them.