Transport Binding
Downloads The code samples used in this user guide have been made available in the Be.Stateless.BizTalk.Factory.Samples GitHub repository.
Let us configure the transport of our sample Microsoft BizTalk Server® Receive Locations and Send Ports. Depending on whether this is a receive location or a send port, the developer will have to configure either an inbound or an outbound adapter.
Transport Adapter
Important There is much more to be said about the configuration of transport adapters and the developer is invited to read the dedicated section about the Adapters for more information.
API wise, configuring the transport adapter of either a receive location or a send port is almost identical. There is however no risk that a developer could inadvertently configure an outbound adapter for a receive location —or, conversely, an inbound adapter for a send port— as this is prevented by the Binding DSL at its core, i.e. the C# would not even compile.
For the illustration’s sake, let us configure the transport adapter of our Bribe Receive Location. You should notice a familiar Binding DSL pattern right now: the constructor is given a configuration lambda.
Transport.Adapter = new FileAdapter.Inbound(
a => {
a.ReceiveFolder = @"c:\file\evil\bribes";
a.FileMask = "*.xml";
a.RenameReceivedFiles = true;
});
The configuration of the transport adapter of our inline Credit Note Receive Location is very similar:
rl.Transport.Adapter = new FileAdapter.Inbound(
a => {
a.ReceiveFolder = @"c:\file\billing\credits";
}
);
Remark We can rely on the configuration properties’ default values and don’t have to configure all of them for any given adapter. Anyway, should we forget to configure a mandatory property, this would be caught by the
ApplicationFixture’sGenerateApplicationBindingtest. Let us suppose we forget to configure theReceiveFolder, then the test would fail complaining that it Did not expect any exception, but found Be.Stateless.BizTalk.Dsl.Binding.BindingException with message “[Credit Note Receive Location] Receive Location’s Transport is not valid: Inbound file adapter has no source folder.”
As illustrated by the following code excerpt, configuring the outbound adapter is unsurprisingly very similar too:
Transport.Adapter = new FileAdapter.Outbound(
a => {
a.DestinationFolder = @"c:\file\tax-evasion";
}
);
Transport Host
Configuring the transport host of any receive location or send port really is a no brainer. For our inline Credit Note Receive Location this would look like:
rl.Transport.Host = "BizTalkServerApplication";
While for our separate Bribe Receive Location that would be:
Transport.Host = "BizTalkServerApplication";
Receive Location’s Transport Specifics
Schedules and Service Windows
BizTalk.Factory’s Binding DSL exposes a rich API to configure all the aspects of receive location’s Schedule and ServiceWindow, as illustrated by the following examples.
With a non recurring service window:
Transport.Schedule = new Schedule {
AutomaticallyAdjustForDaylightSavingTime = true,
StartDate = new DateTime(2022, 1, 20),
StopDate = new DateTime(2022, 2, 14),
TimeZone = TimeZoneInfo.Utc,
ServiceWindow = RecurringServiceWindow.None
}
With a daily recurring service window:
Transport.Schedule = new Schedule {
...
ServiceWindow = new DailyServiceWindow {
StartTime = new Time(8, 0),
StopTime = new Time(20, 0),
From = new DateTime(2022, 1, 20),
Interval = 4
}
}
With a weekly recurring service window:
Transport.Schedule = new Schedule {
...
ServiceWindow = new WeeklyServiceWindow {
StartTime = new Time(8, 0),
StopTime = new Time(20, 0),
From = new DateTime(2022, 1, 20),
Interval = 2,
WeekDays = BtsDayOfWeek.Monday | BtsDayOfWeek.Friday
}
}
With a monthly recurring service window based on calendar days:
Transport.Schedule = new Schedule {
...
ServiceWindow = new CalendricalMonthlyServiceWindow {
StartTime = new Time(8, 0),
StopTime = new Time(20, 0),
Months = Month.January | Month.April | Month.July | Month.October,
Days = MonthDay.Day01 | MonthDay.Day08 | MonthDay.Day15 | MonthDay.Day22 | MonthDay.Day29,
OnLastDay = true
}
}
With a monthly recurring service window based on ordinal days:
Transport.Schedule = new Schedule {
...
ServiceWindow = new OrdinalMonthlyServiceWindow {
StartTime = new Time(8, 0),
StopTime = new Time(20, 0),
Months = Month.January | Month.March | Month.June,
Ordinality = OrdinalType.First,
WeekDays = BtsDayOfWeek.Monday | BtsDayOfWeek.Friday
}
}
Remark Custom
ScheduleandServiceWindowclasses could be written in an environment sensitive way —see Environment Overrides— and will be given the opportunity to provide different configurations according to the target environments for which the application bindings are generated.
Remark When trying to compile some of the previous samples, the compiler might complain that The type ‘BtsDayOfWeek’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘Microsoft.BizTalk.ExplorerOM, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. In this case, the developer should reference the
BizTalk.Server.2020.UtilitiesNuGetpackage.In doing so the developer might causes another compilation to arise, namely, The type ‘BtsDayOfWeek’ exists in both ‘Microsoft.BizTalk.ExplorerOM, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ and ‘Microsoft.BizTalk.Messaging, Version=3 .0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’.
Fixing this problem is more involved and requires the developer to define a
C#extern alias. Assigning an alias to a specific assembly that is part of a multi-assemblyNuGetpackage is not supported by Visual Studio user interface. It is however fairly easy to edit the project file, i.e.Org.Anization.Accounting.Bindings.csproj, and add the following excerpt:<ItemGroup> <Reference Include="Microsoft.BizTalk.ExplorerOM"> <Aliases>ExplorerOM</Aliases> </Reference> </ItemGroup>and rewrite the source file’s using directive as follows —notice the
Explorer::prefix:using ExplorerOM::Microsoft.BizTalk.BtsScheduleHelper;
Send Port’s Transport Specifics
Retry Policies
A send port’s transport expose a configurable retry feature. The BizTalk.Factory’s Binding DSL API surfaces it as a RetryPolicy class, which exposes 2 properties:
- a
Retry countwhose type is integer; - a
Retry intervalwhose type is aTimeSpan, this way freeing the developer of having to remember the time unit in which to express the interval duration before the next attempt to send the message.
Transport.RetryPolicy = new RetryPolicy {
Count = 3,
Interval = TimeSpan.FromHours(2)
};
Every seasoned Microsoft BizTalk Server® developer knows that there is a default retry policy that every send port inherits. Faithful to this principle, every send port declared and configured through BizTalk.Factory’s Binding DSL will have the same default retry policy unless otherwise specified. This default policy is explicitly available through the static Default property of the RetryPolicy class.
using Be.Stateless.BizTalk.Dsl.Binding;
Transport.RetryPolicy = RetryPolicy.Default;
Remark For the record, the
RetryPolicy.Defaultdoes not have hardcodedCountandIntervalvalues but rather fetches them from the configuration classes being part of the native Microsoft BizTalk Server® API.
Environment Sensitive Retry Policies
Recall that a custom RetryPolicy class could be written in an environment sensitive way —see Environment Overrides— so as to be given the opportunity to provide different configurations according to the target environments for which the application bindings are generated.
BizTalk.Factory’s Binding DSL has done precisely that and comes with a predefined set of environment sensitive RetryPolicies made available together with its Naming Convention —see Be.Stateless.BizTalk.Dsl.Binding.Conventions NuGet package. BizTalk.Factory defines three not so arbitrary retry policies:
- a
RealTimeone, which features no retry at all; - a
ShortRunningone, which features 6 retries, one every 5 minutes, thus attempting to deliver a message for a total period of 30 minutes; - a
LongRunningone, which features 72 retries, one every hour, thus attempting to deliver a message for a total period of 3 days.
Each of these policies is environment sensitive in its own way:
-
the
RealTimeone will always be the one actually configured. not matter what the target deployment environment; -
the
ShortRunningone will be replaced by theRealTimeone in every target deployment environment but thePREPRODUCTIONandPRODUCTIONones; -
the
LongRunningone will be replaced by theRealTimeone in theDEVELOPMENTorBUILDtarget deployment environments, and by theShortRunningone in theACCEPTANCEtarget deployment environment.
The whole idea behind these policies is that the developer expresses his actual intent in the code, but the configuration is smart enough to avoid long periods of message delivery attempts in non production environments, therefore speeding up the tests that can rapidly became operationally painful otherwise.
Service Windows
A service window restricts the send port to work during certain hours of the day. It is exposed by the send port’s ServiceWindow property, which is a class exposing 2 properties:
Should you wonder how to configure a service window and instantiate a Time type, the intellisense will guide you through.
Transport.ServiceWindow = new ServiceWindow {
StartTime = new Time(11, 12, 13),
StopTime = new Time(23, 22, 21)
};
Remark A custom
ServiceWindowcould be written in an environment sensitive way —see Environment Overrides— and will be given the opportunity to provide different configurations according to the target environments for which the application bindings are generated.