BizTalk 2020 BRE pipeline framework mapping issue

BRE pipeline framework (BPF) is an extremely powerful pipeline component that simplifies common message manipulations using ready-made BRE vocabularies, so you can create robust BizTalk messaging scenarios without writing code.

If you would like to learn more about it, you can find my previous blog post and Integration Monday Video demonstrating some of its amazing capabilities.

The BRE pipeline framework officially supports BizTalk Server 2010, 2013, and 2013 R2. The BRE vocabularies are based on .NET facts, some of which rely on BizTalk Server DLLs; so understandably, it is expected to encounter some issues when any of these underlying DLLs introduce a breaking change in newer BizTalk versions: 2016 & 2020.

A couple of years ago, Mark Brimble mentioned a breaking change in BizTalk 2016 [Microsoft.BizTalk.Interop. SSOClient] DLL version which impacted the framework’s SSO-related feature & provided a fix for it in his blog post.

The issue

I have been using BPF for quite some time in several projects, and during a pre-migration assessment phase for one of our projects, I encountered a critical error in the framework with BizTalk 2020 solution, which was working fine in BizTalk 2016.

A message sent to adapter "FILE" on send port is suspended. 
Error details: There was a failure executing the send pipeline... 
Reason: Cannot access a disposed object. 
Object name: 'StreamViewOfIStream.Seek'.

The BPF trace showed the root cause of this exception and its location in the framework source code.

Exception Type: System.Exception Message: 
Exception encountered while trying to execute map - 
No overload for method 'Transform' takes '4' arguments 
TargetSite: Void  Execute(Microsoft.BizTalk.Message.Interop.IBaseMessage ByRef, 
Microsoft.BizTalk.Component.Interop.IPipelineContext) 
Source: BREPipelineFramework.SampleInstructions

The BizTalk 2016 solution to be migrated leveraged BPF dynamic transformations, this error is because of a breaking change in Microsoft.XLANGs.BaseTypes introduced in BizTalk 2020; ITransform is now obsolete, it has been used by BPF to perform dynamic transformations. The new replacement is ITransform2 along with its Transform method which takes different parameters, as indicated in the exception details.

Although ITransform is declared obsolete, technically it is still there and can be used with its old Transform method, so why did it fail in the framework?

Resolution

Interestingly, the culprit was because of a documented design decision by the framework creator Johann Cooper to use dynamic keyword for some objects in BPF class: [TransformationInstruction.cs]; where he was actually trying to accommodate for a previous breaking change in transformation types between BizTalk 2010 and BizTalk 2013, while trying to make it future proof for later releases.

XPathDocument input = new XPathDocument(inmsg.BodyPart.GetOriginalDataStream());
pc.ResourceTracker.AddResource(input);
dynamic transform = transformMetaData.Transform;
Stream output = new VirtualStream();
transform.Transform(input, transformMetaData.ArgumentList, output, new XmlUrlResolver());

One usage of dynamic keyword in this class was for the TransformMetaData object, which was resolved into the new ITransform2 type in runtime in BizTalk 2020; and as mentioned earlier, this new type requires a different set of parameters for its Transform method, and thus the exception occurred. 

The fix I did was simple, least intrusive, and should work for BizTalk 2013 solutions onward; I replaced the dynamic keyword with the actual type ITransform, build, GACed the BREPipelineFramework.SampleInstructions DLL, and restarted the BizTalk host instances; afterwards, the BRE pipeline framework mapping feature worked fine in BizTalk 2020.

XPathDocument input = new XPathDocument(inmsg.BodyPart.GetOriginalDataStream());
pc.ResourceTracker.AddResource(input);
ITransform transform = transformMetaData.Transform;
Stream output = new VirtualStream();
transform.Transform(input, transformMetaData.ArgumentList, output, new XmlUrlResolver());

For code wizards out there, please let me know if you have a better solution.

4 Comments