Mapping Code Pairs in the WABS Mapper

By Nick Hauenstein

This post is the twenty-third in a weekly series intended to briefly spotlight those things that you need to know about new features in BizTalk Server 2013.

Assuming that one of the major benefits of using Windows Azure BizTalk Services is being able to offload some of our EDI processing to the cloud, then a major use case for the new WABS mapper becomes EDI mapping. One of the fun tasks that comes out of that is dealing with code pairs (if you’re interested in the on-premise side of this problem, the best coverage to date is found here). In this post, I’m going to examine how one might approach this problem using the new tooling available in the WABS SDK.

Give Me an Example of Code Pairs

Maybe you’re reading this and thinking to yourself, “I don’t really care about EDI, but WABS looks interesting,” and you still want to be able to gain something from this discussion without getting buried in the esoterica that is EDI. If that’s the case for anyone out there, here’s an example of the problem I’m going to try to solve using the WABS mapper.

We have an input that is a repeating record of items where there is a qualifier that describes that type of item we’re looking at, and a value that provides the value of the item. Consider this schema:

image

Here we have (at some point in the schema) a list of phone numbers, identified by a Type field element (our qualifier) and the Number field element (our value). The Type field is defined as follows:

image

We have an output that is a flat listing of items where we have a set of fields representing a few of these different types of numbers:

image

So what we are trying to do is iterate through the list of numbers in the input, map over the value for the item with the qualifier Mobile for the CellNumber output, and grab the value of the Home qualified number and toss it into the HomeNumber output field. It’s something that looks trivial, and yet is annoying to do en masse using the BizTalk Mapper:

image

In a Land Without FLATTENING Value MAPPERS

So what does this look like when brought over to the land of WABS using .trfm style maps? Well, looking into the toolbox, we do have an item called Conditional Assignemnt, which is essentially a Value Mapper:

image

If we run with that (combined with some Logical Expression map operations, we end up with something like this:

image

Unfortunately, this isn’t a Value Mapper (Flattening) type map operation. As a result, this actually will only work if we are interested only in a single qualifier, and that qualifier happens to show up in the first code pair that appears in the document.

So what do we do now? Do we reach to XSLT and code it up by hand (after-all, it is super easy to pull off)? Let’s take a look at how the migration tool that comes with the SDK handles this scenario:

image

It adds two MapEach operations to the map, that are configured something like this:

image

As you can see, the MapEach was made to be conditional upon the Type field element being compared to a constant string input. However, this conditional check is repeated inside the MapEach operation within the chained Logical Expression and Conditional Assignment map operations. While the map technically works as generated by the tool, it looks horrible, and it really feels like there ought to be a better way.

Another Approach

If you don’t want to use the MapEach approach (which really wouldn’t be so bad if our two nodes weren’t hanging out at the root as siblings), then we can take advantage of the ability of the new mapper to generate lists of items in memory while working through the mapping (really this is kind of similar to the Table Looping and Extracting functoid).

In order to make that happen, we use the Create List map operation, and then at some point inside include the Add Item operation to add items to the list. The Create List operation is configured to include the names of the fields of each item in the list. It then includes the ForEach operation with a nested Add Items. The ForEach is pointed to by the parent repeating node of our code pairs. The Add Items operation is pointed to by each value we want to include for each source item:

image

Here’s what the configuration of the Create List map operation looks like:

image

Once we have the list created, we can select values out of the list using the Select Value operation (in fact we’ve used two of them):

image

Does it Work?

Technically, both approaches worked, and took this input, and generated the output shown below it:

image

image

I’m going to be honest here, it still feels comparatively clunky, and I’m probably going to be reaching for that XSLT override pretty frequently. That is, unless there’s yet another way that’s cleaner and more simple than those presented thus far (this is one of those posts that I hope to revisit in the future with a correction showing an even better way to approach the problem).

Next Week

Next week, I will be wrapping up this series and shifting focus back to day-to-day BizTalk Development and all the fun things that we’re actively working on there.

Until then, happy mapping with shiny new tools!

What the BizTalk Server 2013 Mapper Updates Mean for You

By Nick Hauenstein

This blog post represents the first in a weekly series that will highlight things you need to know about new features in BizTalk Server 2013. This week we will look at the new mapping engine and how the underlying changes in the engine might effect the behavior you see when using the BizTalk Mapper.

If you look at the list linked above, you find this:

The Mapper uses the XSLCompiledTransform class. Previous BizTalk Server versions used the XslTransform class, which is obsolete. The XSLCompiledTransform class provides performance enhancements, including:

  • Once the Load method completes successfully, the Transform method can be called simultaneously from multiple threads.
  • The new XSLT processor compiles the XSLT style sheet to a common intermediate format. Once the style sheet is compiled, it can be cached and reused.

For more information on the XSLCompiledTransform class, go to XslCompiledTransform Class.

The mapper now uses the XslCompiledTransform class, a class which was the result of a redesign of the XSLT architecture in the Visual Studio 2005 release (.NET 2.0 timeframe).  While load time of a transform using this class can be longer (since the transform must be compiled upon load), if cached it can yield a 4-fold performance improvement for transforms. Will we see this same level of improvement when used within the context of a BizTalk map? Not quite, but it will definitely be noticeable.

There is a fairly detailed blog post on the XslCompiledTransform class from the XmlTeam written around that time as well. I’m not going to re-hash all of that content here, though you should definitely take a look at the table under the Discretionary Behaviors heading. That table will unveil some things (read: strange edge cases) that used to “just work”, but will now cause exceptions.

Instead of focusing on performance improvement or weird edge cases, in this post, I wanted to look at something a little more common. It surfaced for our team as we were migrating some custom functoids from BizTalk Server 2010 to BizTalk Server 2013. Essentially what we found was that if you attempted to return a null value from a custom functoid, you would receive this error message:

ErrorFunctoidException

For the benefit of those using Google-fu to attack the same problem, the exception message reads: “Extension functions cannot return null values.”

Really this exception would occur regardless of using a custom functoid. Indeed, you can re-create the same behavior with a Scripting functoid returning null out of an inline C# method.

How to Return Null

This all begs the question, how am I supposed to return null? Well there are a few different cases to consider.

If you’re returning null because it’s cleaner than an empty string, but empty string is not considered a special value on its own, then it’s fairly simple. Toss a null coalescing operator between whatever value might be null and string.Empty. That was the fix that handled our case nicely:

[sourcecode language=”csharp”] public string GetError(string lookupId)<br>{<br>return CachedDatabaseAccess.GetError(new Guid(lookupId)) ?? string.Empty;<br>} [/sourcecode]

While that will cause the desired result in the destination message in this case, if I wanted to output null to the destination message I have a few choices still. I can still return string.Empty which will create an empty node in the document, use one of the Logical functoids to prevent a node from being created when it does not return true, or use the Nil Value functoid to set set the output as nil (assuming the destination schema allows it).

Passing Null Around

But what if I’m returning that null value so that it can be passed to another functoid? If both are scripting functoids and they’re both using inline script, I can do this quite easily by making use of a global variable within the map (in the screenshots below it is named result1), and then writing my code to access that in order to request the raw result.

NOTE: This is also a pattern we encourage for maintaining the state of .NET objects through chained functoids (since if they are returned directly the ToString method is called)

scriptfunc1

scriptfunc2

That’s all fine and good when things are inline C#, but what if I’m wanting to pass an earlier null value as an input to an external assemblies? Well that’s where things get a little bit trickier. Best bet there right now is to establish a special non-null value that can represent null, and pass that to an external method that wraps a call to the method you actually want to call and translates that value. Either that, or write custom functoids that can share a set of ThreadStatic values and have one of them wrap the call to the external method (though that might be a little bit overkill).

Wrapping it Up

Even though I’ve spent my time talking about one small annoying aspect of upgrading, let me tell you it’s a worthwhile price to pay for the massive performance improvements you’re going to see.

If you want to see how that custom functoid turned out, and interact with it yourself, be sure to check out one of our upcoming BizTalk Server 2013 Developer Deep Dive courses!

See also: