Overview
Microsoft BizTalk Server is a rich and robust integration platform and is nearing its twentieth birthday(!). Hundreds, if not thousands, of customers have made significant investments over the years developing their integration solutions on BizTalk Server. As they move workloads to Azure to either run both in conjunction with BizTalk Server and within Azure natively, they would like to be able to leverage those investments with minimal refactoring.
Azure Logic Apps is an integration cloud service which allows users to schedule, automate, and orchestrate tasks, business processes, and workflows. Logic Apps functionality both overlaps and complements functionality in BizTalk, but quite helpfully, it also allows for the reuse of existing BizTalk artifacts, such as schemas and maps.
BizTalk maps transform messages between different schemas, and use a number of tools within the map to manipulate data during the transformation. The maps can also utilize external .NET assemblies for these transformations, but because of how BizTalk references these assemblies natively, the maps need some changes in order to be able to reference those assemblies when run in Logic Apps. This article shows how to edit a map created in BizTalk to utilize external assemblies when run in Logic Apps.
Scenario
For the purpose of this blog, we will setup a small solution consisting of two schemas, a BizTalk map, as well as an external .NET assembly. The full solution of BizTalk artifacts and sample files is available here.
In this scenario, we have two sample schemas: Foo, representing our source schema, and Bar, representing the target.
We also have a .NET Framework class library, called MapperAssemblies, which contains a small class with two trivial methods: AddTodayToValue, which will simply append today's day of the week value to the input value, and ConcatValues, which concatenates the input values.
using System;
namespace MapperAssemblies
{
public class TransformValues
{
public string AddTodayToValue(string input)
{
return $"{input} today is {DateTime.Now.DayOfWeek.ToString()}";
}
public string ConcatValues(string val1, string val2)
{
return string.Concat(val1, val2);
}
}
}
As per most libraries used in BizTalk, this assembly has been signed and added to the global assembly cache (GAC).
Finally, we have the map: This map performs a simple transform of the incoming two values from Foo to the three values in Bar.
Each of the three functoids pictured is referencing the sample assembly code, for exmple:
Testing the map with the following sample input
<ns0:Foo xmlns:ns0="http://MapWithAssmeblyReference.FooSchema">
<Val1>Value 1</Val1>
<Val2>Value 2</Val2>
</ns0:Foo>
Will yield the following output
<ns0:Bar xmlns:ns0="http://MapWithAssmeblyReference.BarSchema">
<Val1>Value 1 today is Monday</Val1>
<Val2>Value 2 today is Monday</Val2>
<Val1Val2>Value 1Value 2</Val1Val2>
</ns0:Bar>
Adding the artifacts to Logic Apps
In order to utilize the BizTalk artifacts in Logic Apps, the artifacts must be stored to an Integration Account in Azure. Integration Accounts are a companion resource to Logic Apps in Azure, and can be used as a container to store integration artifacts such as maps, schemas and assemblies, as well as certificates and trading partner agreements.
Create the Integration Account
Adding Schemas
For both the Foo and Bar schemas, perform the following steps:
Adding the map
This step is not quite as intuitive as adding the schemas because BizTalk maps files (btm) are not natively supported by Logic Apps. However, as BizTalk files compile to XSLT, the output XSLT can be loaded to the Integration Account.
Adding the Assembly
Adding the Logic App
While there are many ways to trigger and test the logic app, in this scenario we will create a simple Logic App with an HTTP Trigger and use Postman to test the Logic App.
Create the Logic App
Testing the Logic App
This scenario will use Postman to test the Logic App, but any equivalent tool can be used.
<ns0:Foo xmlns:ns0="http://MapWithAssmeblyReference.FooSchema">
<Val1>Value 1</Val1>
<Val2>Value 2</Val2>
</ns0:Foo>
Looking at the "Runs" history will display an error in the Transform XML step. The specific error will be similar to the following:
"Code": "Invalid XsltContent",
"Message": "An error occured while processing map. 'Cannot find a script or an extension object associated with namespace 'http://schemas.microsoft.com/BizTalk/2003/ScriptNS0'.'"
Understanding the error
Looking inside the XSLT generated by the BizTalk map will show us the source of the error. When BizTalk generates the XSLT, it leaves a namespace reference to the assembly (ScriptNS0), but does not explicitly reference the assembly, which causes Logic Apps to throw the error as it does not know which assembly to associate with this.
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 ScriptNS0" version="1.0" xmlns:ns0="http://MapWithAssmeblyReference.BarSchema" xmlns:s0="http://MapWithAssmeblyReference.FooSchema" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/s0:Foo" />
</xsl:template>
<xsl:template match="/s0:Foo">
<xsl:variable name="var:v3" select="string(Val1/text())" />
<xsl:variable name="var:v4" select="string(Val2/text())" />
<ns0:Bar>
<xsl:variable name="var:v1" select="ScriptNS0:AddTodayToValue(string(Val1/text()))" />
<Val1>
<xsl:value-of select="$var:v1" />
</Val1>
<xsl:variable name="var:v2" select="ScriptNS0:AddTodayToValue(string(Val2/text()))" />
<Val2>
<xsl:value-of select="$var:v2" />
</Val2>
<xsl:variable name="var:v5" select="ScriptNS0:ConcatValues($var:v3 , $var:v4)" />
<Val1Val2>
<xsl:value-of select="$var:v5" />
</Val1Val2>
</ns0:Bar>
</xsl:template>
</xsl:stylesheet>
Fixing the error
In order to tell Logic Apps how to associate this reference with the uploaded assembly, we need to tweak the XSLT. To do this we will need to know the assembly details, the name of the namespace for the helper class, as well as the class name and method signatures of all referenced methods.
As shown in the sample below, we will add an msxsl:script element to the generated XSL which will help Logic Apps associate the script with the assembly. The key parts to the element are:
For this example, the modified XSLT will look like this (note the msxsl:script element):
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 ScriptNS0" version="1.0" xmlns:ns0="http://MapWithAssmeblyReference.BarSchema" xmlns:s0="http://MapWithAssmeblyReference.FooSchema" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0">
<msxsl:script language="C#" implements-prefix="ScriptNS0">
<msxsl:assembly name="MapperAssemblies, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c62342917314647d" />
<msxsl:using namespace="MapperAssemblies" />
<![CDATA[public string AddTodayToValue(string input){ TransformValues helper = new TransformValues(); return helper.AddTodayToValue(input); }]]>
<![CDATA[public string ConcatValues(string val1, string val2){ TransformValues helper = new TransformValues(); return helper.ConcatValues(val1, val2); }]]>
</msxsl:script>
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/s0:Foo" />
</xsl:template>
<xsl:template match="/s0:Foo">
<xsl:variable name="var:v3" select="string(Val1/text())" />
<xsl:variable name="var:v4" select="string(Val2/text())" />
<ns0:Bar>
<xsl:variable name="var:v1" select="ScriptNS0:AddTodayToValue(string(Val1/text()))" />
<Val1>
<xsl:value-of select="$var:v1" />
</Val1>
<xsl:variable name="var:v2" select="ScriptNS0:AddTodayToValue(string(Val2/text()))" />
<Val2>
<xsl:value-of select="$var:v2" />
</Val2>
<xsl:variable name="var:v5" select="ScriptNS0:ConcatValues($var:v3 , $var:v4)" />
<Val1Val2>
<xsl:value-of select="$var:v5" />
</Val1Val2>
</ns0:Bar>
</xsl:template>
</xsl:stylesheet>
Retesting the Logic App
After modifying the XSLT, we need to re-upload the modified file to the Integration Account.
Re-run the test in Postman. The Runs history in the Logic App should indicate a successful run, and there should be a response body in Postman with the values which are generated in the C# assembly.
Summary
In this scenario, we looked at how to modify the XSLT generated by the BizTalk mapper to correctly reference an external assembly when the map is run in Logic Apps.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.