Calling .NET Components From Inline XSLT In BizTalk

Here’s one for you. Last week I encountered a particularly tricky multi-part mapping scenario. I had to build a destination message that contained groupings from the two source messages. Each record in the first source message created a destination node, and each record in the second source message created a destination node directly beneath the related first source record. To make matters tougher, every destination record has an attribute containing a sequential number. So out of this …


The destination was supposed to look like this …

  <Node1 page=”1″><Node1>
  <NodeRelatedToNode1 page=”2″></NodeRelatedToNode1>
  <NodeRelatedToNode1 page=”3″></NodeRelatedToNode1>
  <Node2 page=”4″></Node2>
  <NodeRelatedToNode2 page=”5″></NodeRelatedToNode2>

The grouping part wasn’t too tough, just used a Scripting functoid with the XSLT Call Template and a little hand written XSL. The hard part was creating the sequential “page” numbers. Those familiar with XSLT know that the “variables” in XSLT are basically constants, so you can’t create a variable and increment it. I considered building some sort of recursion to get my incremented number, but in the end, decided to call a custom .NET component from my map’s XSLT. I built a C# component that had a member variable, and a method called “GetNext()” which incremented and then returned the next sequential number. I then set my map’s Custom Extension XML to an XML document referencing my custom component. Now in my XSLT Call Template I could get the next “page” number each time I built a destination node. Neat!
See here for an example of doing this.

Here’s where a “quirk” was introduced. When I deployed this map, and ran multiple documents through it, the first document had it’s paging correct (e.g. pages 1-5), but the next messages had the wrong values (e.g. 6-10, 11-16, etc). What was happening was that somehow this custom C# component was being shared! The “increment” kept counting on each orchestration call! My C# component wasn’t built as a “static” object, and I assumed that the scope of each custom object was the individual map (or orchestration) instance.

I still have no idea why this happened, but to ensure it wouldn’t keep happening, I added a method to the custom component called “Reset()” which set the counter to 0. Then at the top of the map I call out to that method to ensure that each map starts its counter at 0.

Thoughts as to why this happens? Wild stuff.

Technorati Tags:

Author: Richard Seroter

Richard Seroter is Director of Outbound Product Management at Google Cloud, with a master’s degree in Engineering from the University of Colorado. He’s also an instructor at Pluralsight, a frequent public speaker, the author of multiple books on software design and development, plus former editor and former 12-time Microsoft MVP for cloud. As Director of Outbound Product Management at Google Cloud, Richard leads a team focused on products that help teams build and run modern software. Richard maintains a regularly updated blog on topics of architecture and solution design and can be found on Twitter as @rseroter.

7 thoughts

  1. Hi Richard,
    This happens because static .NET components “live” in handler’s context: in our case in BizTalk host instance or IIS if the map runs in SOAP receive location. Unfortunately your solution with Reset() function may cause problems if you have several instances of the same orchestration running simultaneously.
    Sorry for bad news :-).

    I’d try to solve this problem with xslt-only approach. Here is one of the options:

    number(substring(local-name(), 5))])”/>
    number(substring(local-name(), 18))])”/>

    Obviously I don’t know your task and this maybe not what you need, but I hope this helps.
    Good luck.

  2. Richard – alternative -> could you consider a Custom Functoid that internally uses the beloved c# that you need?

    xslt super fast though 🙂

    Nice one.

  3. Hi Richard,

    It is strange to know that this is happening for non static variables. can you please share a snippet so that i can regenerate this shared scenario.

    This arcticle is uprooting my basics 🙂

    1. Hi there. Unfortunately, this was quite a while ago, and I don’t have the original code sitting around anymore. Hopefully there’s enough of a description here if you’d like to re-create it!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.