2

I have some code that needs to run sub-second that translates the output of XML from one system into different XML. The translation file can change at any time, so I am loading a compiled XSLT transform for each time that I do the transformation.

I was doing some formatting in XSLT, but decided that in the future I might want to expand the scripting to do other things, so I added a script tag using C# into the XSLT transform.

In my development environment on my machine, I tested the speed and it compiled the transform in around 200ms. This code will ultimately run in Azure, but sometimes that is slightly slower than my machine.

Once all my testing was done, I published to Azure and tested. To my horror, Azure does the compilation in 10000ms instead. I am able to re-write my current code using only XSLT functions, but was wondering if the community might help me understand why Azure was SOOOOO slow.

I do understand that the XSLT transform has to spin up a CodeDomProvider using CodeDomProvider.CreateProvider, but even in Azure that should not take 10 seconds I would think.

My Azure instance is using an S3 service plan (400 total ACU, 7GB memory), and I never go over 15% utilization.

I removed "EnableDocumentFunction" from the XsltSettings and that seemed to fix it at first. It turns out that the XsltCompiledTransform might be cached, because it I wait about 30 seconds between calls, it still takes around 10 seconds to run the compilation. With the "EnableDocumentFunction" turned on, I didn't have to wait between calls.

If I remove the script from the XSLT code (and the XsltSettings), the transform compiles very quickly in Azure.

Here is the code I was using:

// C# code
string Xslt = ...; // Shown below
using (StringReader srt = new StringReader(Xslt))
{
    using (XmlReader xrt = XmlReader.Create(srt))
    {
        XslCompiledTransform xslt = new XslCompiledTransform();
        XsltSettings xsltSettings = new XsltSettings() { EnableScript = true };
        xslt.Load(xrt, xsltSettings, null); // This takes 10 seconds on Azure, 200ms in dev
    }
}

XSLT transform

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:user="urn:my-scripts">
  <xsl:output method="xml" indent="yes" />

  <msxsl:script language="C#" implements-prefix="user">
    <!--<msxsl:assembly name="System.Web" />
    <msxsl:using namespace="System.Web" />-->
    <![CDATA[
        public string FormatCurrency(decimal Currency)
        {
            return Currency.ToString("###0.00###");
        }
        public string Upper(string Text) { return Text.ToUpper(); }
    ]]>
  </msxsl:script>

  <xsl:template match="ROOT">
    <!-- … (Short XSLT script) -->
  </xsl:template>

</xsl:stylesheet>

I expect Azure to work similarly to my development machine. I realize that creating a CodeDomProvider might take longer because of security in the AppDomain, but 10 seconds seems ridiculous.

Robert
  • 21
  • 2
  • Do you need to embed the C# code in the XSLT code or can't you just set it up in a C# class of its own you use as an extension object by passing it with an `XsltArgumentList` and `AddExtensionObject` to the `Transform` method? – Martin Honnen Aug 23 '19 at 15:12
  • The idea behind putting the C# code into the XSLT was that we can dynamically change the transform if necessary. We are loading the transform string from SQL, and we can update that live in production as opposed to needing to push a new version of the Web App to change the transform. – Robert Aug 23 '19 at 15:16
  • I don't think is a good idea to embed a foreign language in order to encapsulate changes over time. It's better to just change the stylesheet. Also, you should use the extension mechanism XSLT already provide in case you want to extend the language capacity. That way all your external code (XSLT invocation, extension implementation) would be compiled/linked at the same time frame. Finally, _extensions should add capacity_ not data flow. That way what most vary is closer to data (your stylesheet) and what less vary is closer to code (your extension). – Alejandro Aug 23 '19 at 16:02
  • I appreciate your suggestion Alejandro, but XSLT does not do everything that C# can do, so I wanted to have C# as an option. I did not want to put any of the functions in the compiled version of the Web App because then I must re-publish the application to make changes, causing downtime on an application that is mission critical. I designed the code specifically for the purpose we mapped out internally, the real question is why Azure can't run it at a reasonable speed. – Robert Aug 23 '19 at 16:16
  • _"but XSLT does not do everything that C# can do"_ Well, it can format a number wich is the same your embeded script is doing. Embeded scripting has showed to be slower against XSLT extension mechanism in many Microsoft frameworks. – Alejandro Aug 23 '19 at 16:35
  • Again, thank you Alejandro, but you are going off course. That was just an example. I actually am using it to generate a new Guid for certain situations, which XSLT cannot do. – Robert Aug 23 '19 at 18:48
  • Robert -- ... XSLT cannot do? :) See this done in XSLT here: https://stackoverflow.com/a/30775426/36305 – Dimitre Novatchev Aug 25 '19 at 03:06
  • Robert -- more than one comment recommended to you **not** to use ` – Dimitre Novatchev Aug 25 '19 at 03:08
  • I appreciate that I shouldn't do scripting in XSLT, and I have removed it for the time being, but I still would like to know if anyone knows why it is so slow in Azure. That is really my question. – Robert Aug 26 '19 at 01:28

0 Answers0