Skip to the content.

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.

  1. 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 type bool with a string for instance:

    Filter = new Filter(
      () => BtsProperties.AckRequired == true
    );
    
  2. 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>
    
  3. It is intuitive to combine predicates through or and and logical operators as the Binding 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>
    
    1. 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 the Exists 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’s XML.

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) };