Skip to the content.

Be.Stateless.BizTalk.Abstractions

Build Pipelines

Latest Release

Release Preview

Overview

Be.Stateless.BizTalk.Abstractions is part of the BizTalk.Factory Runtime Package. This component provides various abstractions over Microsoft BizTalk Server®’s message contexts and context properties.

Message Context Abstractions

There is some amount of idiosyncrasies coming with Microsoft BizTalk Server® and the API to manipulate —i.e. reading, promoting, or writing— message context properties certainly comes with its shares of oddities.

Message Context API

First and foremost, accessing the context property must be done in two very distinct ways depending on whether the property needs to be accessed from an IBaseMessage or an XLANGMessage-based message instance. The IBaseMessage API is even more awkward as one must most often instantiate some sort of context property descriptor in order to get a QName that will ultimately allow one to get both the context property’s local and namespace names to pass to the API method.

Then, the value returned be the reading API is always of type object and it must always be explicitly casted to the exact concrete type of the property, which requires extra caution to handle null values when reading value type properties.

Finally, deleting a property value from the message context is generally awkward as none of the IBaseMessage and XLANGMessage API exposes a Delete() method. Does one have to assign a null value or an empty string to the property? Does this work the same way with both IBaseMessage and XLANGMessage APIs?

Take a look at the following couple of code samples that demonstrate how to read context properties with the native APIs.

Sample 1 - Accessing context properties using the built-in IBaseMessage API.

public void ProcessMessage(IBaseMessage message)
{
    ...

    var messageTypeProperty = new BTS.MessageType();
    string messageType = (string) message.Context.Read(
        messageTypeProperty.Name.Name,
        messageTypeProperty.Name.Namespace);

    var enqueuedTimeProperty = new SBMessaging.EnqueuedTimeUtc();
    object value = message.Context.Read(
        enqueuedTimeProperty.Name.Name,
        enqueuedTimeProperty.Name.Namespace);
    DateTime enqueuedTime = value != null ? (DateTime) value : default;

    ...
}

Sample 2 - Accessing context properties using the built-in XLANGMessage API.

public void ProcessMessage(XLANGMessage message)
{
    ...

    string messageType = (string) message.GetPropertyValue(
        typeof(BTS.MessageType));

    object value = (DateTime) message.GetPropertyValue(
        typeof(SBMessaging.EnqueuedTimeUtc));
    DateTime enqueuedTime = value != null ? (DateTime) value : default;

    ...
}

Now, contrast them with the following 2 code excerpts that demonstrate the use of a unique, regular, and type-safe API to manipulate message context properties. This new strongly-typed API is made available through extension methods provided by BaseMessage as wrappers around the built-in IBaseMessage and XLANGMessage APIs.

Sample 3 - Accessing context properties using BizTalk.Factory’s IBaseMessage extension methods.

public void ProcessMessage(IBaseMessage message)
{
    ...

    string messageType = message.GetProperty(BtsProperties.MessageType);

    DateTime? enqueuedTime = message.GetProperty(SBMessagingProperties.EnqueuedTimeUtc);

    ...
}

Sample 4 - Accessing context properties using BizTalk.Factory’s XLANGMessage extension methods.

public void ProcessMessage(XLANGMessage message)
{
    ...

    string messageType = message.GetProperty(BtsProperties.MessageType);

    DateTime? enqueuedTime = message.GetProperty(SBMessagingProperties.EnqueuedTimeUtc);

    ...
}

Notice that besides being shorter, they are more importantly identical, regardless of whether the message is an IBaseMessage or an XLANGMessage instance. They do not require any explicit casting. They leverage Nullable<T> for properties that are value types and would otherwise not support null values without explicit special case handling.

For the record, BizTalk.Factory moreover provides IBaseMessageContext extension methods that support the exact same API to either delete, promote, read or write context properties given an IBaseMessageContext object, see BaseMessageContext.

MessageContextProperty<T, TR> Abstraction

The previous extension-method-based API comes with 2 requirements:

  1. Each context property that needs to be accessed must derive from MessageContextPropertyBase. This usually means that the property must be defined as a MessageContextPropertyBase in a Property schema, but as one will see, the property could be defined in plain C# if one does not require the property to take part into subscription filters (e.g. send port’s filters);

  2. A MessageContextProperty<T, TR> accelerator needs to be instantiated for each context property that needs to be accessed via this API.

While the original IBaseMessage API only requires a pair of namespace and local name strings, this API requires types to be defined. But this is not really an issue as the XLANGMessage API requires types to be defined anyway. The benefits of defining such types therefore far outweigh their costs:

Because instantiating these context property’s type-accelerators on demand is tedious and cumbersome, BizTalk.Factory readily provides most of them as static properties defined in a bunch of classes:

Remark Take notice of another Microsoft BizTalk Server® oddity: the SB-Messaging adapter does not make use of the CustomBrokeredMessagePropertyNamespace context property in its own XML namespace, but uses instead the CustomBrokeredPropertyNamespace context property in the WCF XML namespace, see WcfProperties;

Context Properties

For each context property that needs to be accessed via the previously mentioned API, a type deriving from MessageContextPropertyBase must be defined so that its MessageContextProperty<T, TR> accelerator counterpart can be defined in turn.

However, not all of the standard or out-of-box context properties are backed by property schemas. They therefore do not have a corresponding MessageContextPropertyBase-derived type definition. To make these properties nonetheless usable through the BizTalk.Factory API, Be.Stateless.BizTalk.Abstractions fills the gap and provides plain C# type definitions —or pseudo property schemas— for the most meaningful ones.

Remark These context properties only need a plain C# type definition and should not be backed by property schemas as they are not intended to be used in publication/subscription filters.

Remark Because these context properties now have corresponding type definitions, they can finally be used in XLANG/s expressions too, for instances:
variable = message(EDI.BGM1_1)
or
message(Be.Stateless.BizTalk.Schemas.BizTalkFactory.DisableTransportRetries) = true.
They still, nonetheless, cannot be used in a subscription filter or correlation set.

Fluent API

Be.Stateless.BizTalk.Abstractions also provides a fluent API, thanks to extension methods defined by the various classes in the Be.Stateless.BizTalk.ContextProperties.Extensions namespace, to speed up and chain the assignment of the context properties it defines or brings to the surface.

Developer Help

Detailed developer help has been provided as XML comments directly embedded in source code. Though developers usually browse through this documentation while developing thanks to, for instance, JetBrains ReSharper quick help —ctrl+shift+F1, an online version of this inlined help has also been provided here for greater reachability: