2009-05-11 9 views
1

J'ai une bibliothèque open-source this que j'ai du mal à corriger un problème ... Cette bibliothèque permet de créer facilement un fichier XML pour stocker les paramètres de l'application. Mais j'ai un problème en enregistrant les changements.Enregistrement de flux XML en C# dit qu'il est utilisé par un autre processus

J'ai une autre application où j'utilise cette bibliothèque et chaque fois que la fenêtre de l'application est redimensionnée, j'appelle la méthode Save() de la bibliothèque pour sauvegarder la taille/position de la fenêtre dans le fichier XML.

La plupart du temps cela fonctionne très bien, tout est sauvegardé. De temps en temps cependant, je reçois une exception disant que le fichier est utilisé par un autre processus.

J'ai vraiment besoin de m'assurer que les modifications sont sauvegardées à chaque fois que la méthode Save() est appelée, j'ai besoin de gérer cette exception ou de l'empêcher de se produire.

Que suggérez-vous pour mieux gérer cette situation?

Le code de la méthode Save() est la suivante:

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(); 
} 
+0

Je vois que vous avez accepté la réponse de mettre l'instruction lock dans et c'est cool, mais je vous conseille d'utiliser toujours l'instruction using dans votre code. Cela garantira que vous nettoyez toujours vos ressources comme prévu. Si vous avez une exception, vous ne fermerez pas le fichier correctement et pourrez toujours avoir un conflit sur le fichier car le verrou n'aidera pas. –

+0

Je m'en sers aussi, merci de votre attention. J'ai accepté cette réponse parce qu'elle a réglé le problème sur cette question.Je n'ai plus l'exception que j'avais et je n'en ai jamais eu de différent (ne disant pas que je ne l'aurai plus dans le futur), donc le problème est résolu. Pourtant, votre information supplémentaire est bonne et c'est pourquoi j'ai voté pour "réponse utile" :) –

Répondre

1

Il se peut que les événements de redimensionnement de la fenêtre se déclenchent si rapidement que la fonction de sauvegarde est appelée, qu'elle est appelée à nouveau avant la fin de la première exécution. Cela entraînerait l'erreur que vous décrivez (l'autre processus utilisant le fichier est ... VOUS!). Try surrounding your code with a lock, thusly:

lock(some_shared_object) 
{ 
    //Your code here 
} 
3

XmlWriter est IDisposable. Vous devriez l'inclure dans une clause using(). http://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspx

+0

Pouvez-vous expliquer pourquoi votre presque sûr je devrais utiliser using() au lieu de lock()? Jusqu'à présent, je comprends les raisons de la serrure et je pense que cela a du sens, pas pour l'utilisation si ... –

+0

Oups; Je me suis peut-être mal exprimé. La clause using() est impérative pour une classe qui implémente IDisposable. Le verrou peut également être nécessaire selon que votre logique de redimensionnement autorise des événements de redimensionnement entrelacés ou simultanés. – Cheeso

1

Vous pouvez également essayer d'utiliser une instruction lock. Il se pourrait que les méthodes se chevauchent les unes les autres.

+0

Pouvez-vous s'il vous plaît être plus précis? Vous ne savez pas ce qu'est une "déclaration de verrouillage" ... –

+0

Il est 99,44% certain que c'est l'instruction using(). Vous n'avez pas besoin de verrou. – Cheeso

+0

Je ne suis pas certain que l'utilisation de() est le problème racine, car il a un appel à XmlWriter.Close(). Je ne vois pas d'exceptions de déglutition de bloc catch, donc je ne vois pas comment il manquerait des exceptions qui s'envoleraient, et c'est la seule façon que Close() ne soit pas appelée de toute façon. – GWLlosa

2

Je dois aller avec une combinaison des réponses déjà données ici.

Votre XmlWriter doit être dans un bloc using pour plusieurs raisons. Vous devez le disposer pour que vos ressources soient libérées le plus rapidement possible. En outre, que faire si vous lancez une exception tout en interagissant avec elle. Le fichier ne sera pas fermé correctement, au moins jusqu'à ce que le finaliseur entre en jeu et libère vos ressources.

Même avec l'instruction using, vous "pourriez" avoir une contention sur le fichier et devez placer le code Save dans une instruction lock. La méthode est non réentrante par nature car le fichier est une ressource partagée. Mettre un verrou autour peut être trop long si vous n'avez pas plusieurs threads, mais vous devez vous assurer que vous avez correctement contrôlé l'accès au fichier.

L'autre chose à prendre en compte est que vous pouvez déplacer l'opération de sauvegarde vers un thread d'arrière-plan pour écrire le fichier. Si vous obtenez un fichier de paramètres volumineux, vous risquez de provoquer des interactions d'interface utilisateur étranges car vous attendez que le fichier soit écrit chaque fois que l'utilisateur redimensionne et que cela se produise dans le thread d'interface utilisateur. Si vous l'avez fait, vous devrez certainement verrouiller l'accès à la ressource de fichier.

Questions connexes