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 APIand are type safe —C#will prevent the developer from comparing a property of typeboolwith astringfor 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 XMLconfiguration 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 orandandlogical operators as theBinding DSLwill 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 XMLconfiguration 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 GenerateApplicationBindingtest 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 XMLconfiguration bindings, making use of theExistsoperator:<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) };