Demystifying Direct Bound Ports - Part 5

Dynamic Direct Bound Ports

A dynamic port allows you to set the address of the logical port to a URI so that at runtime the message can be routed to the correct service to handle the request and the service can then send to the indicated endpoint.  In BizTalk Server 2006 the same can be done for direct bound ports. 

Setting the address of a port is done by assigning a URI to the Microsoft.XLANGs.BaseTypes.Address property of the port:

 

Port_1(Microsoft.XLANGs.BaseTypes.Address) = “https://contoso.com/myService”;

The general format of a port address is:

<adapterAlias><endpointAddress>

 

A port address is made up of the adapter alias that ultimately maps to a transport, and the actual endpoint as is meaningful to the adapter.  So an adapter alias of https:// will have a URL and a FILE:// will have a URN or a reference to a local file on disk.

This of course begs the question of, “what does a direct bound port URI look like?” 

Direct bound port address’ have the following format:

 

msgbox: <PartnerService> #DirectPortFlavor# <port-type>

 

So for a direct bound port the transport, what would typically be the adapter alias, is the literal msgbox: . The rest is the endpoint address which, for direct bound ports, is a partner service and a port. The #DirectPortFlavor# indicates how the partner service will be interpreted.  Let’s look at the address of each flavor of a direct bound port.

Message Box Direct Bound Port Address

There is no address for a message box direct bound port as it doesn’t make sense since it is a pure publish or subscribe into the message bus (i.e. message box).

Partner Direct Bound Port Address

A partner direct bound port has the following format:

msgbox: <orchestration> #DirectPort# <port-type>

 

In this case the partner service is the orchestration the port is bound to.  The <orchestration> part is the strong name of the orchestration and has the format:

namespace.orchestrationTypeName, assemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef

and <port-type> is the strong name of the port type and has the format:

namespace.portType, assemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef.

 

The direct port flavor is the literal #DirectPort# and indicates that the partner service is an orchestration.

 

Here’s an example of what an address would look like:

msgbox:MyTests.TestOrchestration, MyTests.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef#DirectPort#MyTests.SomeDirectBoundPortType, MyTests.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef

 

Self-Correlating Direct Bound Port Address

A self-correlating direct bound port has the following format:

msgbox: <portServiceId> #selfCorrelated# <port-type>

 

In this case the partner service is the <portServiceId> which is the unique identifier, GUID, given to the port when the orchestration was instantiated and <port-type> is again the strong name of the port-type for this port and has the format:

 

namespace.portType, assemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef.

 

The direct port flavor is the literal #selfCorrelated# and indicates that the partner service is a service instance identifier.

Here’s an example of what an address would look like:

msgbox:aabbccdd-0011223344-eeff-5566778899aa #selfCorrelated#MyTests.SomeSelfCorrelatingPortType, MyTests.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9876543210abcdef

Scenario for using a self-correlated dynamic direct bound port

When doing asynchronous inter-orchestration communication, the typical way of correlating a message to a particular instance of an orchestration is by creating a correlation-set, initializing it with particular property values received or sent in a message, then following that correlation-set on a receive shape.  This can make your orchestration more complex if the values of the properties that you need to correlate on are not in the message when it is originally received forcing you to construct a new message with the correlation properties properly set and sending that message somewhere (it has to be sent to be able to initialize the correlation-set but the destination can be some null orchestration (i.e. an orchestration with just a receive shape)[1]).  Another pattern for inter-orchestration communication correlation is when you have a send and receive on separate one-way ports in a loop and you are using the send port to initialize the correlation set and the receive port to follow.  In this case you must unwind the loop (the first send must be outside of the loop) because you cannot initialize a correlation-set inside of a loop (a correlation-set can only be initialized once) thus making your orchestration even more complex[2].  To get around this extra correlation complexity you can use a self-correlating port that under the covers will manage the responsibility of correlating a message back to the current instance of the orchestration.

In the past the only way we would be able to use a self-correlated direct bound port was by passing the port as a parameter to a ‘started’ orchestration so that it can asynchronously send a message back to the instance of the orchestration that started it. 

Today in an expression shape you can save the port address of the self-correlated direct bound port in a message,

 

Msg1.ReturnAddress = SendPort1(Microsoft.XLANGs.BaseTypes.Address);

 

 send it to a partner orchestration and when the partner needs to communicate back to the instance of the orchestration that sent the original request it can set the address of a direct bound port to the port address that was saved in the message. 

 

ResponsePort1(Microsoft.XLANGs.BaseTypes.Address) = Msg1.ReturnAddress;

 

This really simplifies the design of the orchestration that is expecting asynchronous responses from its partner orchestrations.

When you create the send side port it doesn’t matter what type of direct bound port you create as you will be overriding its address.  I would recommend keeping each side as consistent direct bound flavors to make it easier to review the design.

 

Now that I have lifted the covers of how the dynamic direct bound ports work you can imagine many different scenarios and design patterns.  A few examples include, versioning, dynamic orchestration calling, and, of course, simplified correlation.

 


[1] When using this pattern of communication be careful as there can be a race condition where a message could be sent to the orchestration before the correlation initialization message is sent. To avoid this ensure that messages that will follow this correlation are not sent until the correlation set is initialized.

[2] Another work around is to declare the correlation set within a scope within the loop so that on each iteration of the loop the correlation set falls out of scope and gets re-instantiated and then properly re-initialized. This may not be a suitable option as there could already be transactional scopes within the loop and adding another transactional scope may cause extra persistence overhead.