Partner direct bound ports provide the capability of having inter-orchestration communication via ports.
To configure a partner direct bound port you must choose the orchestration and port for the ‘Partner Orchestration Port’ property. When configuring the two partner ports you must have one side select the orchestration.port it will communicate with and the other side will select its own orchestration.port. This is a little non-intuitive but will be explained in the sections below. Also the port types for both ports must be the same, which implies that the message-types must also be the same. This is one of the places where the Type Modifier property on the port-type matters. To be able to direct bind to a partner port the port-type type modifier must either be internal for orchestrations within the same assembly or public to allow an orchestration from another assembly to bind to it. Finally, the polarities of the ports must be opposite. In other words, if one side is a send port then the other side must be a receive port.
There are two communication patterns that can be created; forward partner direct binding and inverse partner direct binding. These two patterns provide explicit inter-orchestration communication. By explicit I mean that there is an intended recipient orchestration (forward partner direct binding) or an intended sender (inverse partner direct binding). You can design implicit partner direct binding by having either the receiver be message box direct bound and create a filter that will accept messages from a particular sending orchestration or have the sender be message box direct bound and promote properties that will match a subscription on the receiving orchestration.
This is the typical communication pattern that is used for partner direct binding. Orchestration A has a partner direct bound send port that will send a message to Orchestration B on its partner direct bound receive port. To configure this forward partner direct binding you must have orchestrationA.sendPort1, which is of type portType1, select orchestrationB.receivePort1, which is also of type portType1, as its Partner Orchestration Port. orchestrationB.receivePort1 will select itself, orchestrationB.receivePort1, as its Partner Orchestration Port.
Figure 6 Forward Partner Direct Binding Configuration
On the sender’s side what this says is, “I will send messages to orchestrationB.receivePort1” and on the receiver’s side it says, “I will receive any messages sent directly to my receivePort1”.
Under the covers when messages are sent out of sendPort1 the orchestration engine will set the following properties:
BTS.Operation to the operation on the port being used.
BTS.PartnerPort to the name of the partner direct bound port configured in the Partner Orchestration Port property
BTS.PartnerService to the strong name of the orchestration referenced in the Partner Orchestration Port property
Note: the strong name of the partner service will usually look something like:
OrchNamespace.OrchTypeName, AssemblyName, Version=184.108.40.206, Culture=neutral, PublicKeyToken=fedcba9876543210
On the receive side the subscription will be (for brevity I will use the BTS namespace instead of http://schemas.microsoft.com/BizTalk/2003/system-properties as you would see in the actual subscription)
BTS.Operation == operation1 And
BTS.PartnerPort == receivePort1 And
BTS.PartnerService == MyTest.OrchestrationB, MyTest, Version=220.127.116.11, Culture=neutral, PublicKeyToken=fedcba9876543210 And
BTS.MessageType == http://MyNamespace#MyRootNodeTypeName
Something to note here is that there is a strong binding from the sender orchestration to the receiver orchestration. By strong binding I mean that the sender orchestration is referencing the receiver’s strong name as its partner service. What this means is that if you want to change the receiver’s side or if you change the version of the receiver’s side you must update the design time configuration of the sender’s port. But the receiver has no explicit knowledge of the sender so the senders’ orchestrations can be updated without affecting the receiver.
This type of forward binding allows you to have multiple senders bound to the same recipient.
Figure 7 N:1 communication
Here orchestrationD would be doing some common asynchronous work needed by many different orchestrations.
This is not the typical communication pattern that is used for partner direct binding as the direction of binding is inverse of its direction of communication. Orchestration A has a partner direct bound send port will send a message to Orchestration B on its partner direct bound receive port. To configure this inverse partner direct binding you must have orchestrationB.receivePort1, which is of type portType1, select orchestrationA.sendPort1, which is also of type portType1, as its Partner Orchestration Port. orchestrationA.sendPort1 will select itself, orchestrationA.sendPort1, as its Partner Orchestration Port.
Figure 8 Inverse Direct Binding Configuration
On the sender’s side what this says is, “I will send a message to anyone who is listening for messages from my send port” and on the receiver’s side it says, “I will receive messages sent from orchestrationA.sendPort1”.
Under the covers when messages are sent out of sendPort1 the logic for setting properties is still the same as it was for the forward case. The orchestration engine will still set the following properties:
On the receive side the subscription will
BTS.PartnerPort == sendPort1 And
BTS.PartnerService == MyTest.OrchestrationA, MyTest, Version=18.104.22.168, Culture=neutral, PublicKeyToken=fedcba9876543210 And
In this case the receiver is strongly bound to the sender implying that if you want to change the receiver’s orchestration or update the version then you must update the sender’s port configuration. The sender has no explicit knowledge of the receiver so the receivers’ orchestrations can be updated without affect the sender.
This type of inverse binding allows you to have a single sender communicate with multiple receivers.
Figure 9 1:N communication
Inverse direct bound ports allows for a recipient list pattern. The recipient list is determined by which receive ports are bound to a particular send port and is maintained as part of the orchestration design. Here either all of the recipient orchestrations can consume any message coming from the send port or they can each have a filter to determine which messages each of the recipients should consume from the sender.
One thing to be careful about is that if you are using a two-way port type with inverse partner direct binding then you must setup your filters to ensure that only one of the recipients will consume (i.e. subscription will match) the message. This is because a solicit-response port is expecting a single response and if multiple recipients get the message, then it will accept the first response and all subsequent responses would be suspended non-resumable. The engine won’t let that happen and it will instead throw an exception when you try to send the message indicating that there would be multiple recipients for a solicit-response request.