23

Ich habe ein kleines Programm geschrieben, das ich App.config Datei ein einfaches AppSetting für eine andere Anwendung ändern kann, und speichern Sie die Änderungen:Kann ConfigurationManager XML-Kommentare in Save() speichern?

//save a backup copy first. 
var cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile); 
cfg.SaveAs(cfg.FilePath + "." + DateTime.Now.ToFileTime() + ".bak"); 

//reopen the original config again and update it. 
cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile); 
var setting = cfg.AppSettings.Settings[keyName]; 
setting.Value = newValue; 

//save the changed configuration. 
cfg.Save(ConfigurationSaveMode.Full); 

Diese gut, bis auf eine Nebenwirkung funktioniert. Die neu gespeicherte .config-Datei verliert alle ursprünglichen XML-Kommentare, jedoch nur innerhalb des AppSettings-Bereichs. Ist es möglich, XML-Kommentare aus der ursprünglichen AppSettings-Konfigurationsdatei beizubehalten?

Here's a pastebin of the full source if you'd like to quickly compile and run it.

+1

Bekam das gleiche Problem hier mit .NET 4.0 – pipelinecache

+1

Auch festgestellt, dass es nur in der appSettings Abschnitt tut. – pipelinecache

+0

Kommentare bleiben auch im Rest meiner .config-Datei erhalten. Ich habe meinen Beitrag aktualisiert, um dies zu berücksichtigen. –

Antwort

26

Ich sprang in Reflector.Net und schaute auf die dekompilierte Quelle für diese Klasse. Die kurze Antwort ist nein, es wird die Kommentare nicht behalten. Die Art, wie Microsoft die Klasse geschrieben hat, besteht darin, ein XML-Dokument aus den Eigenschaften der Konfigurationsklasse zu generieren. Da die Kommentare in der Konfigurationsklasse nicht angezeigt werden, gelangen sie nicht zurück in das XML.

Und was dies noch schlimmer macht ist, dass Microsoft alle diese Klassen versiegelt, so dass Sie keine neue Klasse ableiten und Ihre eigene Implementierung einfügen können. Sie können nur die Kommentare außerhalb des AppSettings-Bereichs verschieben oder die Klassen XmlDocument oder XDocument verwenden, um stattdessen die Konfigurationsdateien zu analysieren.

Entschuldigung. Dies ist ein Randfall, den Microsoft gerade nicht geplant hat.

2

Wenn Kommentare sind kritisch, könnte es nur sein, dass die einzige Möglichkeit ist, um die Datei manuell (via XmlDocument oder die neuen Linq-ähnliche API) lesen & speichern. Wenn diese Kommentare jedoch nicht kritisch sind, würde ich sie entweder gehen lassen oder sie als (wenn auch redundante) Datenelemente einbetten.

2

Hier ist eine Beispielfunktion, die Sie verwenden könnten, um die Kommentare zu speichern. Sie können ein Schlüssel/Wert-Paar gleichzeitig bearbeiten. Ich habe auch ein paar Sachen hinzugefügt, um die Datei schön zu formatieren, basierend auf der Art, wie ich die Dateien häufig benutze (Sie können das leicht entfernen, wenn Sie wollen). Ich hoffe, dass dies jemand anderem in Zukunft helfen könnte.

public static bool setConfigValue(Configuration config, string key, string val, out string errorMsg) { 
    try { 
     errorMsg = null; 
     string filename = config.FilePath; 

     //Load the config file as an XDocument 
     XDocument document = XDocument.Load(filename, LoadOptions.PreserveWhitespace); 
     if(document.Root == null) { 
      errorMsg = "Document was null for XDocument load."; 
      return false; 
     } 
     XElement appSettings = document.Root.Element("appSettings"); 
     if(appSettings == null) { 
      appSettings = new XElement("appSettings"); 
      document.Root.Add(appSettings); 
     } 
     XElement appSetting = appSettings.Elements("add").FirstOrDefault(x => x.Attribute("key").Value == key); 
     if (appSetting == null) { 
      //Create the new appSetting 
      appSettings.Add(new XElement("add", new XAttribute("key", key), new XAttribute("value", val))); 
     } 
     else { 
      //Update the current appSetting 
      appSetting.Attribute("value").Value = val; 
     } 


     //Format the appSetting section 
     XNode lastElement = null; 
     foreach(var elm in appSettings.DescendantNodes()) { 
      if(elm.NodeType == System.Xml.XmlNodeType.Text) { 
       if(lastElement?.NodeType == System.Xml.XmlNodeType.Element && elm.NextNode?.NodeType == System.Xml.XmlNodeType.Comment) { 
        //Any time the last node was an element and the next is a comment add two new lines. 
        ((XText)elm).Value = "\n\n\t\t"; 
       } 
       else { 
        ((XText)elm).Value = "\n\t\t"; 
       } 
      } 
      lastElement = elm; 
     } 

     //Make sure the end tag for appSettings is on a new line. 
     var lastNode = appSettings.DescendantNodes().Last(); 
     if (lastNode.NodeType == System.Xml.XmlNodeType.Text) { 
      ((XText)lastNode).Value = "\n\t"; 
     } 
     else { 
      appSettings.Add(new XText("\n\t")); 
     } 

     //Save the changes to the config file. 
     document.Save(filename, SaveOptions.DisableFormatting); 
     return true; 
    } 
    catch (Exception ex) { 
     errorMsg = "There was an exception while trying to update the config value for '" + key + "' with value '" + val + "' : " + ex.ToString(); 
     return false; 
    } 
} 
+0

Code ist nicht kompilieren. Fehler in dieser Zeile: if (lastElement? .NodeType == System.Xml.XmlNodeType.Element && elm.NextNode? .NodeType == System.Xml.XmlNodeType.Comment) –

+0

Der?. ist ein neuer Notationsstil mit VS2015 und .net 4.6. Es führt einfach einen Null-Check durch, bevor Sie die Eigenschaft erhalten. Sie können das ersetzen mit: if ((lastElement! = Null && lastElement.NodeType == System.Xml.XmlNodeType.Element) && (elm.NextNode! = Null && elm.NextNode.NodeType == System.Xml.XmlNodeType .Comment)) –

+0

Vielen Dank, ich überprüfe erneut –

Verwandte Themen