23

Ho scritto una piccola utility che mi permette di cambiare un semplice appSetting per il file App.config di un'altra applicazione, e quindi salvare le modifiche:Può ConfigurationManager conservare i commenti XML su Save()?

//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); 

Questo metodo funziona bene, tranne che per un effetto collaterale. Il file .config appena salvato perde tutti i commenti XML originali, ma solo nell'area AppSettings. È possibile conservare i commenti XML dall'area AppSettings del file di configurazione originale?

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

+1

avuto lo stesso problema qui con .NET 4.0 – pipelinecache

+1

anche scoperto che lo fa solo nella sezione appSettings. – pipelinecache

+0

I commenti vengono mantenuti anche nel resto del mio file .config. Ho aggiornato il mio post per riflettere questo. –

risposta

26

Sono entrato in Reflector.Net e ho esaminato la sorgente decompilata di questa classe. La risposta breve è no, non manterrà i commenti. Il modo in cui Microsoft ha scritto la classe è di generare un documento XML dalle proprietà sulla classe di configurazione. Poiché i commenti non vengono visualizzati nella classe di configurazione, non riescono a ritornare nell'XML.

E ciò che rende questo peggio è che Microsoft ha sigillato tutte queste classi in modo da non poter derivare una nuova classe e inserire la propria implementazione. L'unica opzione è spostare i commenti all'esterno della sezione AppSettings o utilizzare le classi XmlDocument o XDocument per analizzare i file di configurazione.

Siamo spiacenti. Questo è un caso limite che Microsoft non ha previsto.

2

Se i commenti sono critiche, potrebbe essere solo che l'unica opzione è quella di leggere & salvare il file manualmente (tramite XmlDocument o la nuova API LINQ-correlati). Se tuttavia tali commenti non sono critici, li lascerei andare o forse prendere in considerazione di incorporarli come (seppure ridondanti) elementi di dati.

2

Ecco una funzione di esempio che è possibile utilizzare per salvare i commenti. Ti consente di modificare una coppia chiave/valore alla volta. Ho anche aggiunto alcune cose per formattare il file in modo corretto in base al modo in cui utilizzo i file (è possibile rimuoverlo facilmente se lo si desidera). Spero che questo possa aiutare qualcun altro in futuro.

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

Il codice non viene compilato. Errori su questa riga: if (lastElement? .NodeType == System.Xml.XmlNodeType.Element && elm.NextNode? .NodeType == System.Xml.XmlNodeType.Comment) –

+0

The?. è un nuovo stile di notazione con VS2015 e .net 4.6. Semplicemente esegue un controllo nullo prima di ottenere la proprietà. È possibile sostituirlo con: if ((lastElement! = Null && lastElement.NodeType == System.XmlNodeType.Element) && (elm.NextNode! = Null && elm.NextNode.NodeType == System.Xml.XmlNodeType .Comment)) –

+0

Grazie, ricontrollare –

Problemi correlati