msxsl scripting for Logic App XSLT

Posted: May 26, 2022  |  Categories: Azure BizTalk

This is story about the limitations of msxsl scripting for XSLT. Before In my last blog I found that I was unable to call an assembly from XSLT if it used System.Net.Http. Nevertheless I describe how to overcome this limitation.

The problem msxsl scripting in Logic Apps

Script blocks are supported only in .NET Framework. They are not supported on .NET Core or .NET 5 or later. Because of this you cannot use the modern System.Net.Http.HttpClient class.

The solution

Refactoring the XSLT reference assembly was hard because I had forgotten all my .Net 4.0 patterns. Firstly I had to replace HttpClient with WebRequest. Microsoft says

Don’t use WebRequest or its derived classes for new development. Instead, use the System.Net.Http.HttpClient class.

WebRequest Class (System.Net) | Microsoft Docs

Nevertheless I had no choice.

Refactoring the msxsl script the XSLT now looks like;

<?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 s1 s2 s0 s3 userCSharp ScriptNS0" version="1.0" xmlns:s3="http://schemas.microsoft.com/Sql/2008/05/Types/Tables/dbo" xmlns:ns0="http://BidOne.Common.Schemas.Internal.Invoice.IF_INVOICE_v2" xmlns:s2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:s0="http://schemas.microsoft.com/Sql/2008/05/TableOp/dbo/BidonecXMLConfiguration" xmlns:s1="http://schemas.microsoft.com/BizTalk/2003/aggschema" xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<msxsl:script language="C#" implements-prefix="ScriptNS0">
		<msxsl:assembly name="BidOne.Common.Helpers.XRef.UOM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=069877e015803704" />
		<msxsl:using namespace="BidOne.Common.Helpers.XRef.UOM" />
    <msxsl:using namespace="System.Net" />
    <msxsl:using namespace="System.IO" />
		<![CDATA[         public static string GetUOM(string UOMURL, string key, string OcpApimSubscriptionKey)
        {
            var remainingTries = 3;
            var finalException = "";

            do
            {
                try
                {
                    remainingTries = remainingTries - 1;
                    string data = GetUOMWebRequest(UOMURL, key, OcpApimSubscriptionKey);
                    return data;
                }
                catch (Exception e)
                {
                    finalException = e.Message;
                }
            }
            while (remainingTries > 0);

            return "UOM not found: " + finalException;
        }
    ]]>
		<![CDATA[        public static string GetUOMWebRequest(string UOMURL, string key, string OcpApimSubscriptionKey)
        {
            //Don't use WebRequest or its derived classes for new development. Instead, use the System.Net.Http.HttpClient class.
            // Using this because we want to call it using msxsl in Azure
            //Script blocks are supported only .Net Framework. They are not supported in .Net Core or .Net 5.0 or later. 
            WebRequest request = WebRequest.Create(UOMURL);

            WebHeaderCollection headers = new WebHeaderCollection();
            headers.Add(key, OcpApimSubscriptionKey);
            request.Headers = headers;
            //Force TLS1.2
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
            ServicePointManager.DefaultConnectionLimit = 9999;

            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                Stream dataStream = response.GetResponseStream();

                StreamReader reader = new StreamReader(dataStream);

                string responseFromServer = reader.ReadToEnd();

                reader.Close();
                dataStream.Close();

                if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Accepted)
                {
                    response.Close();
                    return responseFromServer;
                }
                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    throw new Exception("No valid API key provided.");
                }
                if (response.StatusCode >= HttpStatusCode.InternalServerError)
                {
                    throw new Exception("There is a problem with the UOMMapping service");
                }
            }
            catch (WebException webException)
            {
                throw webException;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return "UOM not found";
        } 
    ]]>
	</msxsl:script>
....[XSLT as before here}

Finally deploying the new assembly and the XSLT to the integration account and we are ready to test. Much to my relief this time the Logic App ran without error and map the UOMs correctly.

Conclusion

Thus if you want to call an assembly from an XSLT in a Logic App make sure you only use C# code that is compatible with the .NET 4.0 framework. Finally I have shown it is possible to replace the Biztalk Cross Referencing functoids with an Azure component.

turbo360

Back to Top