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
’sGenerateApplicationBinding
test. 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
Schedule
andServiceWindow
classes 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.Utilities
NuGet
package.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-assemblyNuGet
package 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 count
whose type is integer; - a
Retry interval
whose 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.Default
does not have hardcodedCount
andInterval
values 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
RealTime
one, which features no retry at all; - a
ShortRunning
one, which features 6 retries, one every 5 minutes, thus attempting to deliver a message for a total period of 30 minutes; - a
LongRunning
one, 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
RealTime
one will always be the one actually configured. not matter what the target deployment environment; -
the
ShortRunning
one will be replaced by theRealTime
one in every target deployment environment but thePREPRODUCTION
andPRODUCTION
ones; -
the
LongRunning
one will be replaced by theRealTime
one in theDEVELOPMENT
orBUILD
target deployment environments, and by theShortRunning
one in theACCEPTANCE
target 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
ServiceWindow
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.