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 Class (System.Net) | Microsoft DocsWebRequest
or its derived classes for new development. Instead, use the System.Net.Http.HttpClient class.
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.