Sometimes, sweeteners can be a bit sour
Posted at 08:00 on 23 February 2009
There's a gotcha with including scripts in your XSL stylesheets using the tag that I blogged about a couple of months ago.
Whenever you load in a stylesheet into an XslCompiledTransform
object, it compiles the scripts into a new in-memory assembly using System.CodeDom
. Every time you re-load the stylesheet, another assembly is created, and as assemblies are not garbage collected and can only be unloaded by unloading your entire application domain, this is a potentially pretty serious memory leak that can quickly bring your application to its knees.
According to Microsoft, this only affects ASP.NET 1.0, but people have reported problems with ASP.NET 1.1 and 2.0 through 3.5 as well.
There are two solutions to this. One is to use XSL extension objects instead of scripts. The other is to use a singleton design pattern, only creating your XslCompiledTransform
once and caching it for future use. In fact, you should be doing this for performance reasons anyway, as parsing and compiling an XSL stylesheet takes time.
A class such as this should prove useful. It caches your XSL stylesheets so that each one will only be parsed into an XslCompiledTransform
the first time:
using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Xml; using System.Xml.Xsl; public static class XslCache { private static Dictionary<string, XslCompiledTransform> cache = new Dictionary<string, XslCompiledTransform>(); [MethodImpl(MethodImplOptions.Synchronized)] public static XslCompiledTransform GetTransform(string xslFile) { // Normalise the path to the XSL file xslFile = new FileInfo(xslFile).FullName; // Return the cached transform if it exists. if (cache.ContainsKey(xslFile)) { return cache[xslFile]; } // Otherwise, load the XSL stylesheet. var transform = new XslCompiledTransform(); transform.Load(xslFile, new XsltSettings(true, true), new XmlUrlResolver() ); cache.Add(xslFile, transform); return transform; } }
XslCompiledTransform
objects are threadsafe once they have been loaded.