Pipeline 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 pipelines for our sample Microsoft BizTalk Server® Receive Locations and Send Ports. Depending on whether the location or port should be a one-way or two-way Message Endpoint, the developer will have to add either a single receive or send pipeline, or both.
Receive Pipeline Binding
We left off our sample Credit Note Receive Location
in a state where the ApplicationFixture
is failing because the “[Credit Note Receive Location] Receive Location’s Receive Pipeline is not defined.”.
In order to be able to add a receive pipeline to our receive location, we need to add a reference to the assembly containing the pipeline we need. Let us reference to the Be.Stateless.BizTalk.Pipelines
NuGet
package from the Org.Anization.Accounting.Bindings
project and configure our receive location’s receive pipeline.
Remark In order to be configure a pipeline, we cannot simply new it and assign it to our receive location or send port; we instead need an API allowing us to configure any of its constituting pipeline components, whatever their pipeline stage, in a
C#
type-safe way.Be.Stateless.BizTalk.Dsl.Binding
provides two generic helper classes that allow us to tap into the configuration of the pipelines and its components:
Notice that
T
is the actual runtime pipeline type and not its Be.Stateless.BizTalk.Dsl.Pipeline definition type; one can therefore configure any actual Microsoft BizTalk Server® pipeline without restrictions.
using Be.Stateless.BizTalk.MicroPipelines;
...
ReceiveLocation(
rl => {
rl.Name = "Credit Note Receive Location";
rl.ReceivePipeline = new ReceivePipeline<XmlReceive>();
})
...
Referencing the Be.Stateless.BizTalk.Pipelines
NuGet
package alone is however not enough as the project’s compilation would fail, complaining that The type ‘ReceivePipeline’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘Microsoft.BizTalk.Pipeline, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. To remedy this issue, let us reference the BizTalk.Server.2020.Runtime
NuGet
package and run the unit tests once more.
Even though the compilation now succeeds, the unit test fails complaining that it Did not expect any exception, but found System.IO.FileNotFoundException with message “Could not load file or assembly ‘Microsoft.BizTalk.PipelineOM, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The system cannot find the file specified.” To remedy this issue, let us reference the same BizTalk.Server.2020.Runtime
NuGet
package from the Org.Anization.Accounting.Bindings.Tests
project too and run the unit tests once again.
Remark
BizTalk.Server.2020.Runtime
contains the Microsoft BizTalk Server® 2020 runtime assemblies, that is to say all the assemblies that are required to be both referenced at development time and be available at runtime —these are typically the assemblies that are deployed in the GAC.
The unit test still fails complaining now that it Did not expect any exception, but found System.IO.FileNotFoundException with message “Could not load file or assembly ‘PipelineObjects, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The system cannot find the file specified.” Let us reference the BizTalk.Server.2020.Utilities
NuGet
package from the Org.Anization.Accounting.Bindings.Tests
project and run the unit tests one more time.
Remark
BizTalk.Server.2020.Utilities
contains the Microsoft BizTalk Server® 2020 non-runtime assemblies, that is to say the assemblies that are only required to be referenced at development time but not to be available at runtime —these are typically the assemblies found in theC:\Program Files (x86)\Microsoft BizTalk Server\Developer Tools
directory.
Receive Pipeline Component Configuration
Configuring the components of a given pipeline obviously requires us to know what are its constituting components but Be.Stateless.BizTalk.Dsl.Binding
has a lot of safety nets to prevent us from making stupid mistakes.
Let us try to configure the Be.Stateless.BizTalk.MicroPipelines.XmlReceive
pipeline. We know that, for simplicity and efficiency’s sake, all the micro pipelines —but the pass-thru ones, for obvious reasons— embed two Be.Stateless.BizTalk.Component.MicroPipelineComponent
s, one before the assembling/disassembling stage and one after it. We also know that a receive pipeline has 4 stages —Decode
, Disassemble
, Validate
, and ResolveParty
.
Remark
Be.Stateless.BizTalk.Dsl.Binding
API has been carefully crafted so as to provide a rich intellisense experience —as illustrated here— that can even help you remember what are the various stages of a receive pipeline.
What receive pipeline’s stage embeds the second Be.Stateless.BizTalk.Component.MicroPipelineComponent
? Is it the Validate
or the ResolveParty
stage? As we are pretty confident this is the latter one, let us try to configure the receive pipeline of our Credit Note Receive Location
.
using Be.Stateless.BizTalk.Component;
using Be.Stateless.BizTalk.Dsl.Binding;
using Be.Stateless.BizTalk.MicroComponent;
using Be.Stateless.BizTalk.MicroPipelines;
using Be.Stateless.BizTalk.Schema;
using Microsoft.BizTalk.Component;
using Microsoft.BizTalk.Component.Utilities;
rl.ReceivePipeline = new ReceivePipeline<XmlReceive>(
p => {
p.Decoder<MicroPipelineComponent>(
c => {
c.Components = new IMicroComponent[] {
new ContextBuilder { BuilderType = typeof(...) }
};
})
.Disassembler<XmlDasmComp>(
d => {
d.DocumentSpecNames = new SchemaList {
new SchemaWithNone(SchemaMetadata.For<Any>().DocumentSpec.DocSpecStrongName)
};
})
.PartyResolver<MicroPipelineComponent>(
c => {
c.Components = new IMicroComponent[] {
new XsltRunner { MapType = typeof(...) }
};
});
});
As usual, let us validate our configuration by running the unit tests. The ApplicationFixture
fails this time complaining that it Did not expect any exception, but found System.InvalidOperationException with message “Stage ‘PartyResolver’ has no ‘MicroPipelineComponent’ component.” Well, we were wrong, the Be.Stateless.BizTalk.Component.MicroPipelineComponent
does not belong to the ResolveParty
stage; it must therefore belong to the Validate
one. Let us fix the code.
rl.ReceivePipeline = new ReceivePipeline<XmlReceive>(
p => {
...
.Disassembler<XmlDasmComp>(
d => {
...
})
.Validator<MicroPipelineComponent>(
c => {
...
});
});
Remark The
API
to configure a pipeline’s components is actually provided together byBe.Stateless.BizTalk.Dsl.Binding
andBe.Stateless.BizTalk.Dsl.Pipeline
. TheAPI
to fetch a given component at a given stage of either a receive pipeline or a send pipeline is actually part of thePipeline DSL
, whose different alternate syntaxes are illustrated by theBinding DSL
through the ReceivePipelineDslGrammarVariant* and SendPipelineDslGrammarVariant* test methods.
For the sake of completeness, here is the configuration of the separate BribeReceiveLocation
type, which is identical, API
wise, to the one of the inline Credit Note Receive Location
.
public BribeReceiveLocation()
{
Name = "Bribe Receive Location";
ReceivePipeline = new ReceivePipeline<PassThruReceive>();
}
Send Pipeline Binding
As illustrated below, configuring a send pipeline’s binding for a port is very similar to configuring a receive pipeline’s binding:
using Be.Stateless.BizTalk.MicroPipelines;
...
SendPort(
sp => {
sp.Name = "Embezzlement Send Port";
sp.SendPipeline = new SendPipeline<XmlTransmit>();
})
...
Remark The embedded C# DSL, being type-safe, naturally prevents the developer from mistakenly trying to configure a port’s send pipeline via the ReceivePipeline<T> configuration helper, or vice versa, a port’s receive pipeline via the SendPipeline<T> configuration helper.
Send Pipeline Component Configuration
Configuring the components of a send pipeline through the SendPipeline<T> generic configuration helper is similar to configuring the components of a receive pipeline with the noticeable exception that a send pipeline has 3 different stages —PreAssemble
, Assemble
, and Encode
.
Remark
Be.Stateless.BizTalk.Dsl.Binding
API has been carefully crafted so as to provide a rich intellisense experience —as illustrated here— that can even help you remember what are the various stages of a send pipeline.
using Be.Stateless.BizTalk.Component;
using Be.Stateless.BizTalk.Dsl.Binding;
using Be.Stateless.BizTalk.MicroComponent;
using Be.Stateless.BizTalk.MicroPipelines;
using Be.Stateless.BizTalk.Schema;
using Microsoft.BizTalk.Component;
using Microsoft.BizTalk.Component.Utilities;
sp.SendPipeline = new SendPipeline<FFTransmit>(
p => {
p.PreAssembler<MicroPipelineComponent>(
c => {
c.Components = new IMicroComponent[] {
new XsltRunner { MapType = typeof(...) }
};
})
.Assembler<FFAsmComp>(
c => {
c.HeaderSpecName = new SchemaWithNone(SchemaMetadata.For<...>().DocumentSpec.DocSpecStrongName);
c.DocumentSpecName = new SchemaWithNone(SchemaMetadata.For<...>().DocumentSpec.DocSpecStrongName);
c.TrailerSpecName = new SchemaWithNone(SchemaMetadata.For<...>().DocumentSpec.DocSpecStrongName);
})
.Encoder<MicroPipelineComponent>(
c => {
c.Components = new IMicroComponent[] {
new ContextBuilder { BuilderType = typeof(...) }
};
});
});