Skip to the content.

Orchestration Binding

Downloads The code samples used in this user guide have been made available in the Be.Stateless.BizTalk.Factory.Samples GitHub repository.

To better support the binding of Microsoft BizTalk Server® orchestrations, BizTalk.Factory’s Binding DSL needs the combined work of the BizTalk.Server.2020.Build NuGet package, which customizes the MSBuild process to generate scaffolding C# code providing strongly-typed orchestration classes —see Be.Stateless.BizTalk.Build.Tasks. As soon as both the BizTalk.Server.2020.Build NuGet package and the project containing the orchestrations are referenced by the application binding configuration project, a custom MSBuild task will generate a <namespace>\<namespace>\<orchestration>OrchestrationBinding.Designer.cs file for each orchestration found in the referenced project.

For an orchestration whose full name is Be.Stateless.BizTalk.Orchestrations.Process, the generated code will be similar to what follows:

namespace Be.Stateless.BizTalk.Orchestrations
{
  using System;
  using System.CodeDom.Compiler;
  using Be.Stateless.BizTalk.Dsl.Binding;
  using Microsoft.XLANGs.Core;

  [GeneratedCodeAttribute("Be.Stateless.BizTalk.Build.Tasks", "2.1.0.0")]
  internal partial interface IProcessOrchestrationBinding : IOrchestrationBinding
  {
    IReceivePort RequestResponsePort { get; set; }
    ISendPort SolicitResponsePort { get; set; }
  }

  [GeneratedCodeAttribute("Be.Stateless.BizTalk.Build.Tasks", "2.1.0.0")]
  internal partial class ProcessOrchestrationBinding : OrchestrationBindingBase<Process>, IProcessOrchestrationBinding
  {
    public struct DirectReceivePort
    {
      public struct Operations
      {
        public struct DirectReceiveOperation { public static string Name = "DirectReceiveOperation"; }
      }
    }

    public struct DirectSendPort
    {
      public struct Operations
      {
        public struct DirectSendOperation { public static string Name = "DirectSendOperation"; }
      }
    }

    public struct RequestResponsePort
    {
      public struct Operations
      {
        public struct RequestResponseOperation { public static string Name = "RequestResponseOperation"; }
      }
    }

    public struct SolicitResponsePort
    {
      public struct Operations
      {
        public struct SolicitResponseOperation { public static string Name = "SolicitResponseOperation"; }
      }
    }

    public ProcessOrchestrationBinding() { }

    public ProcessOrchestrationBinding(Action<IProcessOrchestrationBinding> orchestrationBindingConfigurator)
    {
      orchestrationBindingConfigurator(this);
      ((Be.Stateless.BizTalk.Dsl.ISupportValidation)(this)).Validate();
    }

    IReceivePort IProcessOrchestrationBinding.RequestResponsePort { get; set; }

    ISendPort IProcessOrchestrationBinding.SolicitResponsePort { get; set; }
  }
}

There are a few remarkable points to notice:

This generated code allows to write explicit and strongly-type application and orchestration binding code, without ever resorting to magic strings at all, similarly to what follows:

public class TwoWaySendPort : SendPort<NamingConvention>
{
  public TwoWaySendPort()
  {
    Name = SendPortName.Towards(...).About(...).FormattedAs.Xml;
    ...
    Transport.Adapter = new WcfWebHttpAdapter.Outbound(
      a => {
        ...
        a.HttpUrlMapping = new HttpUrlMapping {
          new(
            Be.Stateless.BizTalk.Orchestrations.ProcessOrchestrationBinding.SolicitResponsePort.Operations.SolicitResponseOperation.Name,
            HttpMethod.Post.Method,
            "/url/path")
        };
      });
  }
}

public class ApplicationBinding : ApplicationBinding<NamingConvention>
{

  ...

  protected override void ApplyEnvironmentOverrides(string environment)
  {
    Orchestrations.Add(
      new Be.Stateless.BizTalk.Orchestrations.ProcessOrchestrationBinding(
        ob => {
          ob.RequestResponsePort = ReceivePorts.Find<TwoWayReceivePort>();
          ob.SolicitResponsePort = SendPorts.Find<TwoWaySendPort>();
          ob.State = EnvironmentDependentValue
            .ForDevelopmentOrBuild(ServiceState.Unenlisted)
            .ForAcceptance(ServiceState.Started)
            .ForProduction(ServiceState.Unenlisted);
          ob.Host = Host.Default;
        }));
  }
}

Because the generated C# code is generated anew at each build, it is guaranteed that the code will not compile anymore should an orchestration port or one of its operations be renamed. Also, because it is generated at each build before the C# compiler performs its work, it is not necessary to commit the generated code to the source repository —but it wouldn’t matter if unnecessarily/mistakenly committed.