Unfortunately, the BizTalk help files contain no detailed information on the direct binding models supported for orchestration ports. This has led to some confusion and misunderstanding amongst BizTalk developers. This article started as an attempt to dispel a few misconceptions which I recently come across. However, the article grew naturally to include a brief introduction to the subject of binding which I hope will be of use to some readers.
Introduction
First, a little background. BizTalk orchestration ports have two major properties. The Communication Pattern property configures ports as either one-way or request-response ports. In addition, ports have a Communication Direction property. In XLANG/s the communication direction, or polarity, of a port is represented by the keywords ‘implements’ and ‘uses’. The idea is that orchestrations implement ports to receive messages from the Message Box, and use ports provided, conceptually, by the orchestration infrastructure, to send messages to the Message Box. For ‘implements’ ports, you configure the Communication Direction property to ‘Receive’ (One-Way) or ‘Receive-Send’ (Request-Response), whilst ‘uses’ ports are configured as ‘Send’ (One-Way) or ‘Send-Receive’ (Request-Response).
Orchestration ports manage the delivery of messages to and from the BizTalk Message Box. Request-Response ports, of course, manage message delivery in both directions, but it is natural to think primarily in terms of the direction of the initial message. Ports obtain messages from the Message Box through subscription. Subscription is primarily a matter of matching rules, composed of predicates, to a set of ‘facts’ associated with messages. These ‘facts’ are expressed in terms of a sub-set of the message context properties. Each message has a collection of metadata property values which represent the context of that message. Subscription only matches rules against those context properties which are marked with a ‘promoted’ flag. Orchestration ports manage the creation of subscriptions for messages to be received and ‘promoted’ context properties for message which are sent.
Binding
In BizTalk, the term ‘binding’ refers to the configuration of orchestration ports in order to control the creation of subscriptions and/or ‘promoted’ properties. Binding is used to control how messages will be routed to or from orchestration ports by the subscription mechanism. Hence, binding often involves additional creation and configuration of messaging Send and Receive ports so that these messaging ports can be bound to orchestration ports. Orchestration ports can also be bound to other orchestration ports.
Messaging Receive ports are bound to orchestration ports by generating subscriptions that select messages based on the value of a message context property called BTS.ReceivePortID. Using features such as filters, correlation sets and role links, it is possible to extend the subscription rules with additional predicates.
BizTalk supports two types of binding on messaging Send ports. Send ports can either be static or dynamic. A static port is configured at deployment to use a ‘transport’ to deliver messages to a specific external end point. Transports are defined by a ‘transport type’, which selects an adapter, and a URI address specifying the location of the external end point. When an orchestration port is bound to a static Send port, the orchestration port is responsible for ensuring that each message is provided with a context property called BTS.SPID which indicates bound Send port. The Send port subscribes to messages whose BTS.SPID is set to a specific Guid value.
In contrast to static Send ports, dynamic ports select transport types and locations dynamically by inspecting various context properties contained on each message delivered to the port by the subscription mechanism. In this way the one Send port can dynamically route messages to different locations via different adapters. When an orchestration port is bound to a dynamic Send port, the orchestration port is responsible for ensuring that the required properties are created within the message context. As well as the BTS.SPID property, these include the BTS.OutboundTransportType, BTS.OutboundTransportLocation and BTS.OutboundTransportCLSID properties.
‘Promoted’ properties
Subscription works only with message context properties that are marked as ‘promoted’. The term ‘promotion’ can be rather confusing because BizTalk has more than one promotion mechanism. BizTalk developers are used to thinking in terms of promoting field values contained within a message into the message context as property values. However, we are specifically talking here about a second, related, mechanism where a subset of context properties, marked internally as ‘promoted’ are automatically copied into a database table when a message is delivered to the Message Box. Once ‘asserted’ in this fashion, BizTalk subscription can then do its matching work. These two mechanisms are typically conflated. When a ‘property field’ is promoted using a schema (or an attribute, if you are using a .NET class as the type definition for message content), the resulting context property will also be marked as ‘promoted’ automatically by Microsoft-supplied disassembler components and also by BizTalk maps. This conflation is very useful, but is also a source of some confusion, because BizTalk developers often don’t understand that there are really two levels of promotion behind the scenes. Using your own code, you can exploit the two mechanisms quite separately in pipeline components, and also, in a rather indirect fashion, within your orchestration code through a combination of ‘direct binding’ and the use of so-called ‘correlation sets’. I say ‘so-called’, because correlation sets really offer a more fundamental facility that can, and often is, used for correlation, but which can be used for other purposes as well.
Binding Configuration
BizTalk supports a facility which allows binding configuration to be changed and amended after initial deployment, without the need to re-compile and re-deploy BizTalk assemblies. Binding configuration can be applied programmatically using the ExplorerOM class library or, with some limitations, the BizTalk WMI classes. The WMI MSBTS_DeploymentService class provides an Import function which allows XML configuration files, called ‘binding’ files to be applied to deployed BizTalk assemblies. Binding files provide a simple way in which bindings for orchestrations within a given assembly can be changed. In addition, binding files can be used to create and configure messaging Receive and Send ports and other BizTalk entities.
Binding Models
BizTalk offers four binding models, each with different characteristics. Each model is really a set of higher level abstractions of the basic BizTalk subscription mechanisms. One of these models is called ‘Direct Binding’. The term ‘direct binding’ is used to suggest that the techniques involved are all about binding one orchestration port directly to another. In fact, this is just one possibility when using this model. I find the term confusing, myself, as other binding models are used to ‘directly’ bind orchestration ports to messaging Send ports. Binding models are really differentiated by the following characteristics:
- support for external binding configuration
- use of static and dynamic messaging Send ports. NB., Receive ports do not support a dynamic model.
- auto-generation of configured messaging ports at deployment time
The four models are:
- ‘Direct’ binding
In this model, orchestration ports do not automatically use or exploit BTS.SPID, BTS.ReceivePortID or other related properties. BizTalk therefore does not manage the binding of orchestration ports to messaging Receive and Send ports. Instead, it is entirely up to developers to control subscriptions and message context in order to route messages. Developers are free, if they wish, to route messages to other orchestration ports. External binding configuration cannot be used with directly bound orchestration ports. Direct binding is the most flexible model, but at a cost. You cannot configure your orchestration ports using binding files, and you generally need to do more programming in order to fully exploit the flexibility on offer.
- ‘Specify later’ binding
In this model, orchestration ports are bound to messaging ports using BTS.SPID, BTS.ReceivePortID or other related properties. Outgoing messages are always routed through static Send ports. Binding configuration can be managed in deployed solutions using binding files or by writing WMI/ExplorerOM code. This is probably the most common model, but is significantly less flexible than direct binding. You have much less control over subscription and ‘promoted’ properties, and can only use this approach to bind orchestration ports to messaging ports.
- ‘Specify now’ binding
This model is similar to the ‘Specify later’ model. However, BizTalk collects transport information at design time, together with pipeline information, and uses this to auto-generate messaging Receive and static Send ports at deployment time. Orchestration ports are then bound to these ports. Binding files can be used, if required, to amend binding configuration on a live system.
- ‘Dynamic’ binding
This model has similarities to the ‘Specify now’ model in that BizTalk collects pipeline information at design time and auto-generates messaging Send ports. Receive ports are not generated, as there is no concept of a ‘dynamic’ Receive port. However, transport information is not configured in the same way. Instead, developers create expressions in orchestrations to assign transport location URIs using the ‘address’ property of orchestration ports. The auto-generated messaging Send ports are dynamic, rather than static. Messages passing from an orchestration through dynamic Send and Send-Receive ports are routed solely on the basis of the orchestration port’s address property which is used to create BTS.OutboundTransportType and BTS.OutboundTransportLocation ‘promoted’ context properties. When a dynamic messaging Send port is enlisted, it creates a set of subscriptions, with one subscription for each adapter. Each subscription tests that the BTS.OutboundTransportLocation property exists, and that the BTS.OutboundTransportType property contains a value identifying the adapter. Hence, not only can dynamic binding route messages to any location based on the address, but also via any registered adapter.
We can summarise the differences between the different binding models as follows:
Messaging Send Ports | External Binding Configuration | Auto-Generated Messaging Ports | ||
Static | Dynamic | |||
Direct | Yes | Yes | ||
Specify Later | Yes | Yes | ||
Specify Now | Yes | Yes | Yes | |
Dynamic | Yes | Yes | Yes |
Let’s now turn our attention more specifically to direct binding, which is the least well understood of the binding models.
Binding Ports Directly
When you select direct binding, you also configure the Partner Orchestration Port property. The very name of this property suggests, as discussed above, that direct binding is all about binding between orchestration ports. However, this really does not do justice to the flexibility available when you select this model. It is perfectly possible to use this model to bind messages to messaging Send ports. The Partner Orchestration Port property always offers at least two options:
- Message Box
This setting provides the greatest flexibility of all. It allows developers full freedom to manage message routing as they please. Orchestration ports do not automatically create ‘promoted’ properties on outgoing messages in order to route those messages to a messaging Send port, and no longer create subscription predicates for received messages based on messaging Receive port identifiers. It should be noted, however, that orchestration ports will still subscribe to specific message types and create a ‘promoted’ MessageType property on sent messages. You can, however, suppress this behaviour easily by using System.Xml.XmlDocument or Microsoft.XLANG.BaseTypes.Any as your message type for incoming or outgoing messages.
- Self Correlated
This option is similar to the Message Box option, but additionally configures an orchestration port to create a CorrelationToken property on outgoing messages, and to subscribe to this property in order to receive the response.
This option is used in two distinct scenarios. In the first, it is used in conjunction with a Send-Receive orchestration port to send a message to the Message Box. The CorrelationToken property is not marked as promoted on the outgoing message. If it was, the message would be immediately returned from the Message Box to the port as the response message, without any further processing. You need to subscribe to the sent message and then, at some future time, return a message to the Message Box with the same CorrelationToken property value, ensuring this time that the CorrelationToken property is marked as ‘promoted’. There are several ways to do this, but we will specifically discuss a general technique later in this article which you might exploit in a second orchestration to generate and return a message with a ‘promoted’ CorrelationToken property.
The second scenario is specific to the Start Orchestration shape. Unlike the Call Orchestration shape, the Start Orchestration shape uses the Message Box to ‘invoke’ another orchestration. A special RPC-type message is generated by the shape and subscribed to by the second orchestration using a special ‘GetObject’ subscription. Parameters are passed to the second orchestration using message parts.
You can create a self-correlated port in an orchestration and then send it as a parameter to a second orchestration using the Start shape. The important thing to understand here is that although the one port appears to be shared across the two orchestrations, the second orchestration will in fact be using a distinct port of the same type. This is in sharp contrast to the behaviour of the Call Orchestration shape. If you pass a port as a parameter to a Call Orchestration shape, you are passing a reference to the one port. In this case the one port is truly shared. You can think of this difference as similar to passing by value (Start Orchestration) and passing by reference (Call orchestration).
Self-correlated ports are typically used with Start Orchestration shapes to implement call-back patterns. An orchestration starts a second orchestration, passing to it a self-correlated port. The port is configured as a Receive port in the first orchestration, and as a Send port in the second orchestration. As we have stated, these are really two distinct ports. The second orchestration can then send messages back to the Message Box via its port. These messages are subscribed to by the original port in the first orchestration.
You cannot use this approach with the Call orchestration shape. Because ports are passed ‘by reference’, the polarity of the port must be same in both orchestrations. The BizTalk compiler will not allow you to pass an ‘implements’ port to a ‘uses’ port parameter, or vice versa. Hence the communication direction of the port you pass in from one orchestration must be the same as the direction of the port reference in the called orchestration. Logically, this prevents any hope of using orchestration port parameters to do ‘call-backs’. The very nature of a call-back means that the communication direction of the port would have to be different in the master and child orchestrations. You might hope that you could create a Send-Receive port in the master orchestration and use the Send part in the child to receive a call-back in the master. This does not work. You won’t be able to compile your code unless you do both the send and the receive in the same orchestration. At an even more fundamental level, orchestration ports always transfer messages to or from the Message Box. They are not endpoints in themselves, and you cannot, somehow, use a single port to directly transfer messages directly to itself!
There is some confusion about the purpose of orchestration port parameters, especially when used with Call Orchestration shapes. When calling child orchestrations, the purpose of port parameters is to simplify and rationalise the application of external binding configuration. When your orchestration design expresses the idea of master and child orchestrations using the Call Orchestration shape, you generally want to think of the message flow through these multiple orchestrations as a single activity. You can create all the required orchestration ports on the master orchestration, and then hand them off to child orchestrations as required. This means that when you manage binding configuration using binding files or programmatically via ExplorerOM or WMI, your bindings can all applied at the master orchestration level alone.
- Partner Ports
In addition to the two settings above, BizTalk supports binding using partner orchestration ports. A partner port is a single port used to bind two orchestrations ports of the same type. Every orchestration port has a specific type, and you can create multiple ports of the same type across different orchestrations. The Partner Orchestration Port property will list all available ports of the same type as the port you are configuring. This includes ports of the same type in your current projects, and any other ports of the same type on public orchestrations in referenced BizTalk assemblies.
Partner ports are used to bind one-way send ports to receive ports or send-receive ports to receive-send ports. The two ports must be of the same type. In almost all cases, they will be in different orchestrations, and the receiving port will be connected to an ‘Activate’ receive shape. To configure the use of partner ports, configure all participating send and receive ports to use direct binding, and then set the Partner Orchestration Port property of each participating port to reference the same partner port. Once configured, Send ports will create three ‘promoted’ properties on each outgoing message. These are the BTS.Operation, BTS.PartnerPort and BTS.PartnerService properties. The values assigned to these properties represent the selected partner port. Each Receive port will subscribe to messages that provide these three properties with the same values.
Partner ports provide an easy-to-configure mechanism for connecting ports in situations where the sent message will always result in instantiation of a new instance of an orchestration. It is very common to use one of the ports involved in message exchange as the partner port. However, ‘third-party’ partner ports can also be used. This approach provides a powerful mechanism for implementing design patterns that require one-to-one, one-to-many, many-to-one or even many-to-many message-exchange relationships between multiple orchestration instances.
Controlling Direct Binding
When using direct binding with the ‘Message Box’ option, you can take full control of which message context properties are marked as ‘promoted’ by orchestration send ports. You must ensure that you have a property definition for each property. BizTalk supplies a large number of pre-defined property definitions, and you can add new property definitions by creating property schemas. If your custom properties are not linked to any message content, remember to select the MessageContextPropertyBase setting for the Property Schema Base property of your definition. In your orchestration code, add message assignment expressions to create and initialise the message context properties using the special XLANG/s syntax for this purpose:
myMessage(MyPropertSchema.MyCustomProperty) = "Purchase Order";
Now create a correlation type that includes the properties you want to mark as ‘promoted’. Correlation types specify a list of defined property definitions. Create a correlation set over the correlation type and assign it to the ‘Initialising correlation set’ property of the send port that will send the message on which you have created the required properties.
When a message arrives at the orchestration send port, the correlation set will be initialised using the property values you assigned to the message context. The correlation set will then be used by the send port to decide which properties should be marked as ‘promoted’. Without the correlation set, the properties would not be marked as ‘promoted’ and so could not be used to route the message via subscription.
Although the above approach uses correlation sets, but is not really an example of correlation! Instead, we are simply using the correlation type as the nearest equivalent in orchestrations to the concept of promoting ‘property fields’ in schemas. This mechanism allows you to fully control the routing of message sent from orchestrations.
To control subscription predicates created by receive ports, use filters and correlation sets. Filters can only be used on ports linked to ‘Activate’ Receive shapes. The use of correlation sets (or self-correlation) to control subscription for non-activation Receive shapes can seem very restrictive. However, it is logical. BizTalk routes messages to specific instances of an orchestration. That instance is either created to handle a message using an activation subscription, or the message is routed to an already running instance of an orchestration. BizTalk insists that instance-specific subscriptions are created for every non-activation Receive shape. The Receive shape must ‘follow’ an already initialised correlation set created either in the same orchestration or in a master orchestration which called or started the current orchestration instance.
I’ll finish be dispelling a couple of misconceptions which I recently come across, and which prompted this article.
- “Direct Binding bypasses the Message Box”.
This is simply not true. In fact, almost by definition, an orchestration port is a port to/from the Message Box. The only mechanism I know of in BizTalk where messages bypass the Message Box is where the Call Orchestration shape is used to directly invoke a sub-orchestration, and messages are passed via parameters. Even the apparently similar Start Orchestration shape uses the Message Box.
- “Direct Binding is only ever used to exchange messages between orchestration ports.”
Not true at all. As we have seen, direct binding allows you to take fuller control over your subscriptions and ‘promoted’ context properties, and therefore over routing within BizTalk. Whilst it is true that you will most typically use this model to bind one orchestration port to another, and while the ‘partner ports’ functionality only supports orchestration ports, you can nevertheless also use direct binding to bind to messaging Send ports.
Why would you wish to do this? In one common scenario you might wish to route messages from an orchestration to a messaging Send port based on a filter expression on that Send port. When you add a filter expression to the port, BizTalk creates a new AND group of predicates. AND groups are ORd, so whatever other predicate groups exist within the port subscription, this new group can be used independently to identify messages. Here is a typical example of the predicates for a Send port that contains a filter:
Rule {
Group0 { MyPropertSchema.MyCustomProperty1 =
True AND MyPropertSchema.MyCustomProperty2 =
"Purchase Order" } OR Group1 {
BTS.SPTransportID = { 29B63190 - A67A - 7819 - 02B4 - 8EA38F255021 }
}
}
In this example, any message delivered to the Message Box with a ‘promoted’ Boolean property called MyPropertSchema.MyCustomProperty1 set to True, and a promoted string property called MyPropertSchema.MyCustomProperty2 set to “Purchase Order” will be routed to the messaging Send port. Use direct binding and correlation sets to create these properties on messages within an orchestration. The BTS.SPTransportID predicate is a standard predicate added by every Send port when it is first created, and exists in its own predicate group.
You could create many messaging Send ports, each with a different filter, and then select which port to route message through simply by setting properties on messages in your orchestration logic and sending the properties back to the Message Box via a directly bound port and correlation set. In effect, this is really a kind of dynamic binding, and is significantly more flexible than the built-in dynamic binding model which is based on a URI address only.