Out of the Angle Brackets
So, your application is crashing and it is crashing in the bad way. After spending hours of debugging and trying different things you figured out that this is this Xslt stylesheet that causes all the problems. How come? XslCompiledTransform is a compiler. It’s a bit different from C# or VB.NET compilers because it runs at runtime but the result of the compilation is basically the same – IL (Intermediate Language) code. One of disadvantages of running compilation at runtime is that compilation issues may have impact on the running application. In the “offline” scenario compiler would just return an error (the one I hate the most is “Internal Compiler Error” – still it will not affect my app at runtime – at worst there is no app). So, compilation may be one source of problems. The other source of problems can be the IL code the stylesheet was compiled to. Here there is not much difference between code generated from Xslt, C# or VB. In any case it is easy to write a program that compiles correctly but misbehaves at runtime (bugs anyone?). Let’s take a look at two most common unexpected exceptions you may hit when working with XslCompiledTransform and ways to resolve them.
This is one is pretty easy. It can happen when you combine embedded scripts or loading stylesheets in debug mode with the not recommended way of using XsltCompiledTransform. The recommended way of using XslCompiledTransform is to load an Xslt stylesheet once and re-use the instance the stylesheet was loaded to for further transformations. Loading the same stylesheet repeatedly should be avoided. The main concern here is performance. XslCompiledTransform.Load() does not mean only “load the stylesheet” but “load and compile the stylesheet”. This is the “compile” part that makes .Load() expensive. There is more to the story though. In some cases when compiling a stylesheet the compiler will create assemblies on the fly. When does this happen? Easy to guess - either when you are using scripts in your stylesheet (to compile scripts the compiler uses CodeDOM which creates assemblies containing compiled code for the scripts) or when loading a stylesheet in debug mode (necessary to make stylesheet debugging work). Why is this important? The dynamically created assemblies are loaded into the AppDomain. Once they are loaded they cannot be unloaded (CLR does not allow unloading a single assembly from an AppDomain – the only way to unload an assembly from an AppDomain is to unload the whole AppDomain). So, if you load a stylesheet in debug mode or a stylesheet containing a script repeatedly you will see that your app is consuming more and more memory. The reason for this are the dynamically created assemblies that cannot be unloaded (Houston, we’ve got a leak!). Eventually, so many assemblies have been created and loaded that it is not possible to load yet another one and you get the OutOfMemoryException. If you just load a stylesheet with a script once (you should avoid loading stylesheets in debug mode in production environment entirely) and re-use the object there will be only one assembly created for your script and you should not see the OutOfMemoryExceptions caused by the Xslt. Most likely you will also see a perf boost which is a result of not compiling the stylesheet many times. Another way to resolve the problem is to compile the stylesheet “offline” (i.e. not at runtime) with the xsltc (xslt compiler, more details in MSDN http://msdn.microsoft.com/en-us/library/bb399405.aspx). This tool will create “regular” assemblies (.dll files) for the Xslt stylesheet and the embedded scripts. To be able to use them in your app you just need to add references. The memory leak problem is resolved – there is no compilation going on at runtime so no temporary assemblies are created.
This exception is bad. It brings the whole process down and there is nothing in your app you can really do about it (starting from .NET Framework 2.0 StackOverflowException is not “catchable”). When using XslCompiledTransform you can get this exception either when the Xslt stylesheet is being compiled or when the transformation is being performed.
StackOverflowExceptions thrown when compiling the stylesheet are rare. There can be just a couple root causes of this problem:
There are a few additional interesting notes:
The conclusion is that web apps running on 64-bit machines are more prone to this problem than non-web apps or apps running on x86 (In fact I don’t remember this problem being reported for non-web apps).
Disclaimer: I believe that most Xslt stylesheets hitting this problem are poorly written. Usually aside from issues with compilation their performance is also bad. I strongly believe that the *right* way of addressing these kinds of issues is to refactor/fix the stylesheet.
In case it is not possible for you to refactor the stylesheet:
Stack overflow thrown when transforming an Xml file.
This one is pretty common and there is one main root cause – your stylesheet is using very deep or infinite recursion. Recursion is the way to emulate “regular” loops (like for, while etc.) in Xslt. Now, if you have a bug in the stylesheet and you never stop the recursion or the recursion is deep you can get the StackOveflowException. It’s not different from other .NET languages like C# or VB where infinite or very deep recursion will result in the same exception. If you have a bug – fix the bug and you should be good to go. If the reason is the deep recursion then it’s a bit more difficult. Obviously you need to change the stylesheet to fix it. There is a couple of things that you can try doing:
Obviously to work around this problem you can try increasing the stack size for the thread the transformation is running on but again – are you really sure you want to do this?
Pawel Kadluczka