Send Port Binding
Downloads The code samples used in this user guide have been made available in the Be.Stateless.BizTalk.Factory.Samples GitHub repository.
Growing our Application
binding sample, let us add send ports to handle the interactions with our Embezzlement
subsidiary and our external Tax-Evading Shell Company
. The developer can choose between 2 alternate syntaxes to declare new send ports: he can use fluent syntactic helpers or separate types.
Fluent Declaration
Using the fluent API, we can add the Embezzlement
send port to our Accounting
application as follows:
public Application()
{
...
SendPorts.Add(
SendPort(
sp => {
sp.Name = "Embezzlement Send Port";
sp.SendPipeline = new SendPipeline<XmlTransmit>();
sp.Transport.Adapter = new FileAdapter.Outbound(a => { a.DestinationFolder = @"c:\file\embezzlement"; });
sp.Transport.Host = "BizTalkServerApplication";
}));
...
}
Separate Type Declaration
If we prefer to declare a separate type for the Tax-Evading Shell
we can define the following class:
using Be.Stateless.BizTalk.Dsl.Binding;
using Be.Stateless.BizTalk.Dsl.Binding.Adapter;
using Be.Stateless.BizTalk.MicroPipelines;
namespace Org.Anization.Accounting
{
public class TaxEvadingShellCompanySendPort : SendPort
{
public TaxEvadingShellCompanySendPort()
{
Name = "TaxEvadingShellCompany";
SendPipeline = new SendPipeline<XmlTransmit>();
OrderedDelivery = true;
Priority = Priority.Normal;
Transport.Adapter = new FileAdapter.Outbound(a => { a.DestinationFolder = @"c:\file\tax-evasion"; });
Transport.Host = "BizTalkServerApplication";
}
}
}
Remark As illustrated, ordered delivery and priority can be configured too.
Filters
Configuring subscription filters thanks to the BizTalk Server Administration Console can rapidly become tedious; even more so if directly written as XML
configuration binding.
BizTalk.Factory
’s Binding DSL
tremendously streamlines and alleviates theses burdens. No more magic strings when configuring filters against, for instances, message types or port names. No more struggle when combining predicates through or
and and
operators.
Let us illustrate some of the main advantages of writing subscription through BizTalk.Factory
’s Binding DSL
.
-
It uses the same context property accelerators that are used by the Message Context Abstraction
API
and are type safe —C#
will prevent the developer from comparing a property of typebool
with astring
for instance:Filter = new Filter( () => BtsProperties.AckRequired == true );
-
It frees the developer from using magic strings for message types or port names —though it should be discouraged to write filter directly against port names as they can easily be altered through the administration console:
Filter = new Filter( () => BtsProperties.MessageType == SchemaMetadata.For<Any>().MessageType && BtsProperties.ReceivePortName == ApplicationBinding.ReceivePorts.Find<EvilBankReceivePort>().Name );
This will produce the following
XML
configuration binding:<Filter> <Filter> <Group> <Statement Property="BTS.MessageType" Operator="0" Value="http://schemas.microsoft.com/BizTalk/2003/Any#Root" /> <Statement Property="BTS.ReceivePortName" Operator="0" Value="Bank of Evil ReceivePort" /> </Group> </Filter> </Filter>
-
It is intuitive to combine predicates through
or
andand
logical operators as theBinding DSL
will take care of redistributing these operators correctly so as to produce valid subscription filters in all cases:Filter = new Filter( () => (BtsProperties.MessageType == SchemaMetadata.For<Any>().MessageType || BtsProperties.ReceivePortName == ApplicationBinding.ReceivePorts.Find<EvilBankReceivePort>().Name) && BizTalkFactoryProperties.EnvironmentTag == TargetEnvironment.ACCEPTANCE );
This will produce the following
XML
configuration binding:<Filter> <Filter> <Group> <Statement Property="BTS.MessageType" Operator="0" Value="http://schemas.microsoft.com/BizTalk/2003/Any#Root" /> <Statement Property="Be.Stateless.BizTalk.Schemas.BizTalkFactory.EnvironmentTag" Operator="0" Value="ACC" /> </Group> <Group> <Statement Property="BTS.ReceivePortName" Operator="0" Value="Bank of Evil ReceivePort" /> <Statement Property="Be.Stateless.BizTalk.Schemas.BizTalkFactory.EnvironmentTag" Operator="0" Value="ACC" /> </Group> </Filter> </Filter>
- It is impossible to write invalid subscription filters even though they can be written in
C#
:
Filter = new Filter( () => BtsProperties.MessageType == null );
This will throw the following exception when the
GenerateApplicationBinding
test method is executed:System.NotSupportedException with message "Cannot translate FilterPredicate "() => (BtsProperties.MessageType == null)" because filter value can be null only if the operator is exists."
By opposition, the following subscription filter is therefore valid:
Filter = new Filter( () => BtsProperties.MessageType != null );
and would produce the following
XML
configuration bindings, making use of theExists
operator:<Filter> <Filter> <Group> <Statement Property="BTS.MessageType" Operator="6" /> </Group> </Filter> </Filter>
For a thorough coverage, the developer is invited to take a look at all the various ways one can write
C#
type-safe subscription filters in the FilterFixture unit testing class, as well as how they translate to binding configuration’sXML
. - It is impossible to write invalid subscription filters even though they can be written in
Backup Transport
Because a send port’s backup transport is optional, it is exposed as a Lazy<T>
type through the BackupTransport
property, which can be configured as follows —in a very similar way to how a send port’s primary transport is configured:
BackupTransport.Value.Adapter = new FileAdapter.Outbound(a => { a.DestinationFolder = @"c:\file\tax-evasion-backup-plan"; });
BackupTransport.Value.Host = "BizTalkServerApplication";
BackupTransport.Value.RetryPolicy = RetryPolicy.Default;
BackupTransport.Value.ServiceWindow = new ServiceWindow { StartTime = new Time(1, 0), StopTime = new Time(23, 0) };