Pregunta

He escrito una pequeña utilidad que me permite cambiar un AppSetting simple para App.config archivo de otra aplicación, y luego guardar los cambios:

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

Esto funciona bien, excepto por un efecto secundario. El archivo .config que acaba de guardar pierde todos los comentarios originales XML, pero sólo dentro del área AppSettings. ¿Es posible para retener los comentarios XML desde el área original AppSettings archivo de configuración?

He aquí un Pastebin de la fuente completo si desea recopilar de forma rápida y ejecutarlo.

¿Fue útil?

Solución

salté en Reflector.Net y mire a la fuente decompilados para esta clase. La respuesta corta es no, no va a retener los comentarios. La forma en que Microsoft escribió la clase es generar un documento XML a partir de las propiedades de la clase de configuración. Dado que los comentarios no aparecen en la clase de configuración, que no lo hacen de nuevo en el XML.

Y Lo que es peor es que Microsoft selló todas estas clases por lo que no se puede derivar una nueva clase e insertar su propia implementación. Su única opción es mover los comentarios fuera de la sección AppSettings o utilizar XmlDocument o XDocument clases para analizar los archivos de configuración en su lugar.

Lo sentimos. Este es un caso extremo de que Microsoft simplemente no planificar.

Otros consejos

Esta es una función de ejemplo que se puede utilizar para guardar los comentarios. Se le permite editar una clave / valor par a la vez. También he añadido algunas cosas para formatear el archivo muy bien sobre la base de la forma en que suelen utilizar los archivos (aquí se puede extraer que si se quiere). Espero que esto podría ayudar a alguien más en el 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;
    }
}

Si los comentarios son críticos, que sólo podría ser que su única opción es leer y guardar el archivo manualmente (a través de XmlDocument o la nueva API relacionada con LINQ). Sin embargo, si esos comentarios no son críticos, ya sea me dejo ir o tal vez consideren la incorporación de ellos como (aunque sea redundante) elementos de datos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top