Andrew's Blog

Random Thoughts of an ASP.Net Code Monkey

Can't Save Your XSL/T File? Have You Closed Your XMLReader?

September 5, 2008 14:08 by Andrew Westgarth

Post Updated on Monday 8th September 2008 - See Below

This week I have been working on a server control for a site I'm working on which reads in an XML file containing some product information and then using an XSL/T file transforms the output into correctly formatted XHTML.  One problem which occurred with the development of the server control was that a colleague of mine who was making modifications to the XSL/T File was unable to save the changes whilst viewing the resultant XHTML in their browser.  At first hand it would appear that it would be a permissions issue, and after much checking of the permissions to confirm they were correct, it was determined this was not the issue. 

My colleague had been able to save changes to the XSL/T after a short while of the page processing which immediately pointed me to the fact that the object was still holding onto the resources.  This was further confirmed with some investigation work which I did with the help of Craig Murphy

The XMLReader object which was reading and transforming the XML using the XSL/T was still holding on to the file and placing a lock on it because the XMLReader object doesn't have a dispose method and so therefore despite my setting the object to nothing, until the garbage collector picked up the objects then the lock on the XSL/T file remained.  Craig suggested I call the XMLReader.Close() method after I had finished processing the XML, this was a method I wasn't aware of and had not seen used in any example when I did my research into the changed syntax since version 2.0 of the .Net Framework. 

Here is a code snippet below of an example of how to use the XMLReader.Close() method to release the locks on resources:

Dim strProductDataXML As String = "ProductData.xml"
Dim strProductDataXSLT As String = "ProductDataTransform.xsl"
Dim sb As New StringBuilder()
Dim sw As New StringWriter(sb)

' Create XSL CompiledTransform to hold XSLT
Dim objXSL As New XslCompiledTransform
' Create XsltSettings to hold XSLT Settings
Dim objXSLTSettings As New XsltSettings(False, True)
' Create XmlReader Object to read the XSLT
Dim objXSLReader As XmlReader
' Create XMLReaderSettings Object For XMLReader Object which will read the XSLT
Dim objXSLReaderSettings As New XmlReaderSettings()
' Create XMLSecureResolver for use with the XSLCompiledTransform
Dim objXMLResolver As New XmlSecureResolver(New XmlUrlResolver(), "http://www.mysite.com/")

'Create Reader Object to read the XSL Transform
objXSLReader = XmlReader.Create(HttpContext.Current.Server.MapPath("~/XSLT/ProductDataTransform.xsl"), objXSLReaderSettings)
' Load the Transform in the XSLCompiledTransform Object, Provide the settings and resolver objects
objXSL.Load(objXSLReader, objXSLTSettings, objXMLResolver)

' Set the Source of the ProductData XML File to be transformed
Dim xmlSource As New XmlTextReader(HttpContext.Current.Server.MapPath("~/XML/ProductData.xml"))
Dim xPathDoc As New XPathDocument(xmlSource)

' Call the close method on the XMLTextReader to release all resources which is attached too.
xmlSource.Close()

' Perform the Transformation and output it to a stringwriter object
objXSL.Transform(xPathDoc, Nothing, sw)
' Call the close method on the XSLReader to release all resources which is attached too.
objXSLReader.Close()

' Set all objects to Nothing to allow the Garbage Collector to remove them
strProductDataXML = Nothing
strProductDataXSLT = Nothing
objXSL = Nothing
objXSLTSettings = Nothing
objXSLReader = Nothing
objXSLReaderSettings = Nothing
objXMLResolver = Nothing
xmlSource = NothingxPathDoc = Nothing

' Return the transformed string
Return sb.ToString()

Now that the XMLReader is closed and has released all of the objects holding on to it, the XSL/T file can be edited and changed without having to wait for the Garbage Collector to remove the objects and release the locks.

 

UPDATE - After reading the comments I have received on this post, I have tidied up the code and made use of the Using structure, to be honest I had forgotten this was available in VB.Net from version 2.0 of the Framework.  The use of the Using structure handles the disposal of the objects and therefore releases the locks on the resources the objects are using.  Below is the updated code sample:

Dim strProductDataXML As String = "ProductData.xml"
Dim strProductDataXSLT As String = "ProductDataTransform.xsl"
Dim sb As New StringBuilder()

' Create XSL CompiledTransform to hold XSLT
Dim objXSL As New XslCompiledTransform
' Create XsltSettings to hold XSLT Settings
Dim objXSLTSettings As New XsltSettings(False, True)
' Create XMLReaderSettings Object For XMLReader Object which will read the XSLT
Dim objXSLReaderSettings As New XmlReaderSettings()
' Create XMLSecureResolver for use with the XSLCompiledTransform
Dim objXMLResolver As New XmlSecureResolver(New XmlUrlResolver(), "http://www.mysite.com")

objXSLReaderSettings.ProhibitDtd = False

'Create objXSL XMLReader Object to read the XSL Transform
Using objXSLReader As XmlReader = XmlReader.Create(HttpContext.Current.Server.MapPath("~/XSLT/" & strProductDataXSLT), objXSLReaderSettings)
    ' Load the Transform into the XSLCompiledTransform Object, Provide the settings and resolver objects    
    objXSL.Load(objXSLReader, objXSLTSettings, objXMLResolver)
    ' Set the Source of the ProductData XML File to be transformed    
    Using xmlSource As New XmlTextReader(HttpContext.Current.Server.MapPath("~/XML/" & strProductDataXML))
        Dim xPathDoc As New XPathDocument(xmlSource)
        Using sw As New StringWriter(sb)
            ' Perform the transformation and output it to a stringwriter object            
            objXSL.Transform(xPathDoc, Nothing, sw)
        End Using
    End Using
End Using

Return sb.ToString()

I'm sure you'll agree it's a lot cleaner and better structured.

Categories: How To
Actions: E-mail | Permalink | Comments (5) | Comment RSSRSS comment feed

Comments (5) -

Richard

Have you thought about using a "Using" statement? It's C# only prior to VS2005, but if you're writing in VB.Net 2.0, that would handle all the closing and disposal of the objects for you, including situations where an error gets thrown in the processing code, something that the example above wouldn't handle.

Richard | September 8 2008 02:13

barryd

Forget close, XmlReaders as disposable objects.

Using XmlReader as New XmlReader

....

End Using

In this case, being pedantic, Dispose and Close perform the same actions; however if there's a Dispose method then you should be looking at wrapping it in a using statement so when if falls out of scope the object releases as soon as possible. As an added bonus the = Nothing really is redundant in .NET; when the object falls out of scope it will be collected in the next sweep anyway, and setting = Nothing doesn't (AFAIK) does not speed this up in any way

barryd | September 8 2008 03:20

Andrew Westgarth

Thanks for the responses. I am working on that area of the site now so will modify and update the blog post with the resultant code.

Andrew Westgarth | September 8 2008 03:32

Andrew Westgarth

I've updated the code to make use of the Using structure - it feels better and looks better too Smile  Also took the time to tidy up a couple of other things in the overall project.  Thanks for all your comments.

Andrew Westgarth | September 8 2008 06:56

TJ

OMG, thank you so much for this, I've been getting really angry at myself for not forming the google query correctly to answer my question.



TJ | May 1 2012 17:54

Pingbacks and trackbacks (1)+



MCTS

Post calendar

<<  December 2024  >>
MoTuWeThFrSaSu
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2024