Introduction

When working in BizTalk, often we will want to have some dynamic behaviour on our sendports, most often for sending a message to a different endpoint. We can use a dynamic port for this, however this has some downsides:

  • Configuration has to be done outside of your port, in an orchestration. This means that you either end up hardcoding your settings in your orchestrations, or you place them externally, for example in the SSO.
  • Much harder to maintain for your administrators, as they don't have easy insight into the settings.
  • Dynamic ports do not allow ordered delivery.
  • There is some impact on performance (https://blogs.msdn.microsoft.com/paolos/2010/07/07/how-to-boost-performance-of-the-esb-routing-and-transform-services-part-1/).
  • In BizTalk versions prior to BizTalk 2013, only the default handler can be used for each transport type.
However, instead of using dynamic ports, we can also use static ports, and override certain properties to allow them for some static behaviour as well.

Property Schema

For this, we will use custom properties which we will set on our message in our orchestration, so let's start by creating a property schema. As we will be promoting the properties from an orchestration, make sure to set the Property Schema Base for each node to MessageContextPropertyBase. In this example we will allow to set an endpoint, which we can set from our orchestration, but you could override any property you want to. If we do not override the endpoint from our orchestration, the default endpoint which is configured on the port will be used.



BRE

We will be using the BRE to decide to which endpoint we will be sending out messages. To pass these properties between our orchestration and the BRE we will be creating a helper message.




In the BRE we will be checking the source of the incoming message, and for certain countries we will send the outgoing message to a specific, non-default endpoint.

Pipeline

Next we will want to set up a custom pipeline, with 2 properties for deciding if the port is a FILE of a WCF port, as we will want to add some additional functionality for these.



public bool IsWcfPort { get; set; }
  
public bool IsFilePort { get; set; }
  
public virtual void Load(IPropertyBag pb, int errlog)
{
    var val = ReadPropertyBag(pb, "IsWcfPort");
    if ((val != null))
    {
        IsWcfPort = ((bool)(val));
    }
    val = ReadPropertyBag(pb, "IsFilePort");
    if ((val != null))
    {
        IsFilePort = ((bool)(val));
    }
}
  
public virtual void Save(IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)
{
    WritePropertyBag(pb, "IsWcfPort", IsWcfPort);
    WritePropertyBag(pb, "IsFilePort", IsFilePort);
}


In the execute method we will check if a custom endpoint has been set in our custom properties, and if so, we will update the OutboundTransportLocation with this endpoint. This will make sure the message will be sent to the correct endpoint. In addition to this, in case the type of the port is FILE, we will create the directory as well. Otherwise, in case the type of the port is WCF, we will have to set the IsDynamicSend property, otherwise the endpoint will be cached and additional calls will be sent to the same endpoint. More information about this can be found on MSDN.


public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
    // Set namespaces
    const string systemPropertiesNamespace = "http://schemas.microsoft.com/BizTalk/2003/system-properties";
  
    // Get custom properties
    var destination = inmsg.Context.Read("Destination", customNamespace) as string;
  
    // In case of File Send port, make sure the destination folder exists
    if (IsFilePort && !string.IsNullOrWhiteSpace(destination) && !Directory.Exists(destination))
    {
        Directory.CreateDirectory(Path.GetDirectoryName(destination));
    }
  
    // In case of WCF Send port, we need to promote IsDynamicSend to prevent the port from caching the configuration
    if (IsWcfPort)
    {
        inmsg.Context.Promote("IsDynamicSend", systemPropertiesNamespace, true);
    }
  
    // Promote OutboundTransportLocation if an endpoint had been set in the custom properties
    if (!string.IsNullOrWhiteSpace(destination))
    {
        inmsg.Context.Promote("OutboundTransportLocation", systemPropertiesNamespace, destination);
    }
  
    // Return message with new promoted properties
    return inmsg;
}


Now that we have our pipeline component created, we can create a pipeline which uses this.



Orchestration

Finally, we will need to create a orchestration which will apply our logic.




The orchestration creates the BRE helper message from a string in a streaming way as described here.


BRE = Eldert.Samples.StaticPortDynamicBehaviour.BusinessComponents.XLangMessageStringConverter.CreateXLANGMessageFromString("<ns0:BRE xmlns:ns0=\"http://Eldert.Samples.StaticPortDynamicBehaviour.Schemas.BRE/2016/3\"><ns0:Action></ns0:Action> <ns0:Destination></ns0:Destination> </ns0:BRE>", "MessagePart");

After this it calls the BRE policy we created earlier to get a custom endpoint if needed.  Using the response, it will set out custom property which will later on be used in our pipeline.

Output(Eldert.Samples.StaticPortDynamicBehaviour.Schemas.Destination) = BRE.MessagePart.Destination;

Port

Now all there is left to do is deploy our application, create our ports, and use our custom pipeline on the sendport.


Code

The complete code for this sample can be downloaded from the MSDN Code Samples Gallery.

See Also

Another important place to find an extensive amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.