XmlDocument.Load is evil
i finally tracked down and fixed a nagging bug in the exyus engine tonight. it goes like this:
whenever i would run tests against my local machine, all went fine for the execution. however, when i attempted to modify the XSLT document tied to a recent request, i'd get an alert from the editor that the file was locked by another process. bummer.
turns out i had been using the XmlDocument.Load
method to load the XSLT file from disk. bad idea! seems the XmlDocument
can leave a lock on the file that may not get cleared until the parent process is cleared (i.e. restarting the ASP.NET process) or the XmlDocument
is finally GC'ed. both unreliable.
the fix was quite easy, though. what i did was open the file using the XmlTextReader
class and pass the reader to the XmlDocument
. even better, i did this within a C# using
block to make sure it gets disposed and marked for GC efficiently. here's my new code for loading the XSLT file from disk:
// use the supplied writer object public void Execute(XmlDocument xmldoc, string xslFileName, ref XmlTextWriter output) { // transform it and send it out Utility util = new Utility(); MvpXslTransform xsldoc = new MvpXslTransform(); xsldoc = (MvpXslTransform)System.Web.HttpContext.Current.Cache.Get(xslFileName); if (xsldoc == null) { xsldoc = new MvpXslTransform(); XmlResolver xmlres = new XmlUrlResolver(); using (XmlTextReader xtr = new XmlTextReader(xslFileName)) { xsldoc.Load(xtr, new XsltSettings(true, false), xmlres); xtr.Close(); } System.Web.HttpContext.Current.Cache.Add( xslFileName, xsldoc, new System.Web.Caching.CacheDependency(xslFileName), System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Default, null); } xsldoc.Transform( new XmlInput(xmldoc.CreateNavigator()), util.GetXsltArgs(), new XmlOutput(output) ); }
notice i am also caching the (compiled) instance of the XSLT document. since i am running all this in ASP.NET, i get a new instance for every request. that means i'd have to compile the sample XSLT document unlimited times. by caching it to memory after the compile, i only need to do this once for the life of the ASP.NET process (or until the underlying XSLT file is changed).