Every now and then as an architect you would get a request to be able to expose a mapping service for another application to consume and the requirement was preferred if the map was exposed over HTTP so it could be called in real time without the message box over head from executing the map internally to BizTalk.

There were a number of solutions which evolved to do this, even the ESB toolkit offered some of these kind of features.

At the same time on Azure, the integration offerings were dabbling with different ways of implementing a map as a service feature. There were new designers which would be interesting for a while but then never kept up to date with visual studio. More recently the Integration Account on Azure is offering mapping capability as part of a premium costing package if your customer is making a heavy bet on Logic Apps.

I was playing around recently and wondering if I could just run a BizTalk map in a Function?

The answer was yes I could

How do I do it?

To start with I created an input and output schema and a simple map as shown in the picture below.

There is nothing complex here and we know from unit testing that we can test a map by calling it directly in C# using the XslCompiledTransform class.

I compiled the BizTalk artefacts in the BizTalk project and left them at that.

Next up I created an Azure function in the normal way and then in the settings I went into the AppService Advanced Editor which allows me to upload stuff to the function. See picture below.

In the function I created a bin directory and uploaded the MapFunction.dll output from my BizTalk project. I also uploaded a number of the BizTalk runtime assemblies (or you can possibly grab these via nuget in the function if its easier).

Next up I used a modified version of the helper class I usually use to test maps when unit testing. This class would instantiate an instance of the map based and then be passed a string which it would use as the input xml for the map and it would return xml.

public class MapExecutor<TMap>

{

private TransformBase _bizTalkMap;

public MapExecutor()

{

var map = (TMap)Activator.CreateInstance(typeof(TMap));

_bizTalkMap = map as TransformBase;

}

public string ExecuteMap(string input)

{

string outputText = string.Empty;

if (_bizTalkMap == null)

throw new ApplicationException(“The map is null, check it inherits from TransformBase”);

//Save input to disk ready to run map

using (var outputStream = new MemoryStream())

{

var outputWriter = XmlWriter.Create(outputStream);

using (var inputStream = new MemoryStream())

{

var writer = new StreamWriter(inputStream);

writer.Write(input);

writer.Flush();

inputStream.Flush();

inputStream.Seek(0, SeekOrigin.Begin);

var inputReader = XmlReader.Create(inputStream);

//Run the map

XslCompiledTransform transform = new XslCompiledTransform();

XsltSettings setting = new XsltSettings(false, true);

transform.Load(XmlReader.Create(new StringReader(_bizTalkMap.XmlContent)), setting, new XmlUrlResolver());

transform.Transform(inputReader, outputWriter);

outputWriter.Flush();

outputStream.Flush();

outputStream.Seek(0, SeekOrigin.Begin);

var outputReader = new StreamReader(outputStream);

outputText = outputReader.ReadToEnd();

}

}

return outputText;

}

public XsltArgumentList GetExtensionObjects(XDocument extObjects)

{

XsltArgumentList arguments = new XsltArgumentList();

foreach (XElement node in extObjects.Descendants(“ExtensionObject”))

{

string assembly_qualified_name = String.Format(“{0}, {1}”, node.Attribute(“ClassName”).Value, node.Attribute(“AssemblyName”).Value);

object extension_object = Activator.CreateInstance(Type.GetType(assembly_qualified_name));

arguments.AddExtensionObject(node.Attribute(“Namespace”).Value, extension_object);

}

return arguments;

}

}

The helper class was pasted directly into the function (or you could put this in a dll if you really wanted) and then I added some using statements for the function and referenced some assemblies in the function like in the below picture.

I then modified the method body for a function which is executed over HTTP so that I can read the body as a string, execute my map then return the response. The picture below shows how simple it is to execute the map.

Now we need to test it so fortunately I can use the testing capability in the Azure portal. I added some sample xml for the input to the function and clicked POST

In the function console I can see my map executes and in the test response I can see my output xml.

In this case my map has successfully been executed

Finally consuming the mapping function is really easy. Above I used to test function capabilities in the portal but I can execute the function over HTTP using code or something like postman. I simply need the url for the function and a key from the portal, then im good to go.

What about helper assemblies?

I haven’t tried this scenario yet, but Im pretty sure it should work. If your map references a custom .net dll you could just upload it to the function and it should just run the same as we do in unit testing in c#.

Are there limitations?

Im sure there will be a number of limitations to this approach, for example some of the functoids in a map will be unusable. An example would be if you wanted to use the database connector functoids they will obviously not have line of sight to the database. Any functoids which don’t have external dependencies should work.

I think if you can get it to work with a C# unit test then you should be able to make it work in a function.

I know I can, but should I?

I think the problem with this approach however is you are almost definitely going to be in a grey area around licensing. I know there are some cases where having a BizTalk Enterprise license allows you to use BizTalk artefacts on non BizTalk servers. Im thinking the BizTalk WCF LOB Adapters and I think there is also a scenario with the rules engine too.

With respect to the developer SDK and runtime its probably more of a grey area and im sure the initial answer would probably be that you cant do this.

What would we like to see?

The use case is a valid use case and has been around for years. I would like to see Microsoft offer BizTalk Enterprise customers something like this simply because BizTalk mapper is really mature and is one of the better mappers out there and if they included a feature in Visual Studio where you could develop a map and just right click and deploy as an Azure Function which generated all of the boiler plate code above, this would be a really simple way to build a reusable mapping service with almost no complex overhead. The map could then be consumed by BizTalk, Logic Apps or any other service as its just an HTTP call.

 

Buy Me A Coffee