One of my pet peeves about the usage of dynamic send ports in BizTalk Server is the loss of flexibility that comes along with the programming model that is generally accepted when using them (I’m normally quite pragmatic rather than puritanical but for some reason this really grinds my gears). The loss of flexibility typically presents itself in the below ways.
- In most scenarios that require dynamic send ports developers will introduce orchestrations into their solutions to setup the properties of the dynamic send port, even when the requirements would be better suited to a messaging only solution.
- When orchestrations are introduced to cater for dynamic send ports they usually contain knowledge of the transport mechanism to be used as well as the send pipeline rather than making use of an external resolver. In my mind this is a loss in terms of separation of concerns and loose coupling.
- When specifying a logical send port in an orchestration to be of a dynamic binding type, you are forced to manually bind the orchestration logical port to a physical dynamic send port rather than making use of property filters, thus introducing a further level of rigidity.
This technet article describes how dynamic send ports could be supported in a messaging only solution which in my view opens the door for a lot of goodness in terms of loose coupling and flexibility. This is done by setting the BTS.OutboundTransportType and BTS.OutboundTransportLocation context properties on the message prior to it being handled by the dynamic send port. It highlights that one isn’t forced down the path of using orchestration to support the usage of dynamic send ports, and even if orchestration is required there is no requirement to make use of the dynamic logical port binding (which is equivalent to a specify-later binding) and one can instead use direct binding and make use of property filters for routing messages to the appropriate dynamic send port.
The aforementioned article only contains a sample which requires the hardcoding of the transport type and URL as parameters of a pipeline component. This blog post will explore taking this concept one step further through the use of the BizTalk BRE Pipeline Framework to conditionally (and thus dynamically) set the transport type and the URL (and potentially other supporting properties for the given transport type) that will be used by a dynamic send port in a messaging scenario.
To start with let’s assume we have a receive location that receives XML messages which contain either a FileName element or an EmailAddress element, these values being promoted to custom context properties (see the schema designer representation of this schema and the property schema below). The existence of these context properties should be used to determine how to handle the message.
If the message contains a FileLocation element then we want to write the message to the specified location. If the message contains an EmailAddress element then it is to be sent out over SMTP to the specified address. To mix things up we will also map the email messages to a flat file format, convert it to a flat file and set the subject of the email to “AITM sample”.
This can be achieved by creating two dynamic send ports (note that if not for the mapping/flat file requirement for the email messages then this could have been achieved with one send port, but I have introduced the extra complication to help you understand what is possible), each one these send ports having filters based on the existence of the aforementioned context properties.
An outbound map can be applied on the dynamic send port that is used to send email messages while no outbound map is specified for the dynamic send port that is used to write to the file system. The dynamic send port that writes the message to the file system will employ a PassThroughTransmit pipeline while the SMTP dynamic send port will employ a pipeline that makes use of the flat file assembler pipeline component.
On our receive location we will make use of a pipeline that contains an XML disassembler pipeline component which is used to promote the relevant context properties as well as the BREPipelineFrameworkComponent pipeline component which we will use to execute our business rules.
The DynamicSendPortResolver policy contains three rules, one for each of the two transport types we are supporting and an additional rule to throw an exception if no transport type can be resolved (just to be on the safe side).
The “Set File Properties” rule is fired when the custom FileLocation context property contains a non-blank value. It sets the BTS.OutboundTransportType context property to FILE, and sets the BTS.OuboundTransportLocation context property to the value of the FileLocation context property.
The “Set SMTP Properties” rule is fired when the custom EmailAddress context property contains a non-blank value. It sets the BTS.OutboundTransportType context property to SMTP, the BTS.OuboundTransportLocation context property to the value of the EmailAddress context property, and sets the SMTP.Subject context property to “AITM sample” as below.
The “Unknown transport” rule is fired when neither the EmailAddress or FileLocation context properties exist or their values are blank. It throws an exception stating “A transport type could not be resolved” as below.
Dropping an XML file into the receive location with a FileLocation element results in the file being written to the file system as below.
Dropping an XML file into the receive location with an EmailAddress element results in the message being mapped and converted to a flat file format and sent out as an email with a subject of “AITM sample” as below.
Dropping a file with neither a FileLocation nor an EmailAddress element will result in the message being suspended as below.
In the above example all the rules to resolve the BTS.OutboundTransportType and BTS.OuboundTransportLocation context properties were placed on the receive pipeline in the receive location. This was purposely done because it is very important that the BTS.OutboundTransportType context property is set to the appropriate transport before the message reaches the dynamic send port as once the message has been received then it is too late to override the adapter to be employed. It is of course still possible to override the BTS.OutboundTransportLocation so you do have some options there. If you want a message to be routed to multiple dynamic send ports with different transports then you will most likely need to introduce an orchestration.
I hope this blog post portrays how dynamic send ports can be used in a more loosely coupled manner.