views:

1338

answers:

4

I have this open-source library that I'm having some trouble fixing a problem... This library allows to easily create an XML file to store application settings. But I'm having an issue saving the changes.

I have another application where I'm using this library and every time that application window is done resizing, I call the Save() method of the library to save the window size/position to the XML file.

Most of times it works fine, everything is saved. Once in a while though, I get an exception saying the file is being used by another process.

I really need to make sure that changes are saved every time the Save() method is called, I need to handle this exception somehow or prevent it from happening.

What are you guys suggestions for best handling this situation?

The code for the Save() method is the following:

public void Save() {
    // Create a new XML file if there's no root element
    if(xDocument.DocumentElement == null) {
        xDocument = new XmlDocument();
        xDocument.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
            "<" + XmlRootElement + ">\n</" + XmlRootElement + ">");
    }

    // OMITTED CODE WAS HERE (NOT IMPORTANT FOR THE PROBLEM)

    // Create a new XML writer for the XML file
    XmlWriter xWriter = XmlWriter.Create(XmlFilePath, new XmlWriterSettings() {
        Indent = true,
        IndentChars = "\t"
    });

    // Sort the XML file using the XSL sylesheet and save it
    xslTransform.Transform(xDocument, xWriter);

    // Clear the buffer and close the XML writer stream
    xWriter.Flush();
    xWriter.Close();
}
+3  A: 

XmlWriter is IDisposable. You should wrap it in a using() clause. http://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspx

Cheeso
Can you explain why your almost certain I should use using() instead of lock()? So far, I understand the reasons for the lock and I think it makes sense, not for the using though...
Nazgulled
Whoops; I may have misspoken. The using() clause is imperative for a class that implements IDisposable. The lock may also be necessary depending on whether your resize logic allows interleaved or concurrent resize events.
Cheeso
+1  A: 

Also you might try using a lock statement. It could be that the methods are overrunning one another.

Spencer Ruport
Can you please be more specific? Not sure what a "lock statement" is...
Nazgulled
It's 99.44% certain it is the using() statement. You don't need a lock.
Cheeso
I'm not certain the using() is the root problem, since he has a call to XmlWriter.Close(). I don't see a catch block swallowing exceptions, so I don't see how he'd miss any exceptions flying out of there, and that's the only way that Close() isn't getting called anyway.
GWLlosa
+1  A: 

It could be the case that the window-resizing-completed events are firing so quickly, that the save function is being called, the called again before it finishes running the first time. This would result in the error you're describing (the other process using the file is... YOU!). Try surrounding your code with a lock, thusly:

lock(some_shared_object)
{
    //Your code here
}
GWLlosa
+2  A: 

I have to go with a combination of the answers already given here.

Your XmlWriter should be in a using block for several reasons. You should dispose it so that your resources are freed as soon as possible. Also, what if you throw an exception while interacting with it. The file wouldn't be closed properly, at least until the finalizer kicks in and frees your resources.

Even with the using statement, you "might" have contention on the file and need to place the Save code in a lock statement. The method is non-reentrant by nature because the file is a shared resource. Putting a lock around it might be over kill if you don't have multiple threads, but you would ensure that you properly controlled access to the file.

The other thing to consider is that you might want to move the saving operation to a background thread to write the file out. If you get a large settings file you might cause strange UI interactions because you are waiting on the file to write every time the user resizes and this happens on the UI thread. If you did this you would definitely need to lock access to the file resource.

Brian ONeil