Может ли ConfigurationManager сохранять комментарии XML для Save ()? - PullRequest
25 голосов
/ 23 декабря 2009

Я написал небольшую утилиту, которая позволяет мне изменить простой AppSetting для файла App.config другого приложения, а затем сохранить изменения:

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

Это хорошо работает, за исключением одного побочного эффекта. Вновь сохраненный файл .config теряет все исходные комментарии XML, но только в области AppSettings. Можно ли сохранить комментарии XML из области AppSettings исходного файла конфигурации?

Вот пастбина из полного исходного кода, если вы хотите быстро скомпилировать и запустить его.

Ответы [ 3 ]

28 голосов
/ 29 декабря 2009

Я вскочил в Reflector.Net и посмотрел на декомпилированный источник для этого класса. Краткий ответ - нет, он не сохранит комментарии. Microsoft написала этот класс для генерации XML-документа из свойств класса конфигурации. Поскольку комментарии не отображаются в классе конфигурации, они не возвращаются в XML.

И что еще хуже, Microsoft закрыла все эти классы, чтобы вы не смогли получить новый класс и вставить собственную реализацию. Единственный вариант - переместить комментарии за пределы раздела AppSettings или использовать классы XmlDocument или XDocument для анализа файлов конфигурации.

Извините. Это крайний случай, который Microsoft просто не планировала.

4 голосов
/ 13 ноября 2015

Вот пример функции, которую вы можете использовать для сохранения комментариев. Это позволяет редактировать одну пару ключ / значение за раз. Я также добавил некоторые вещи для удобного форматирования файла, основываясь на том, как я обычно их использую (вы можете легко удалить это, если хотите). Я надеюсь, что это может помочь кому-то еще в будущем.

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;
    }
}
2 голосов
/ 27 декабря 2009

Если комментарии критичны, возможно, единственный вариант - прочитать и сохранить файл вручную (через XmlDocument или новый API, связанный с Linq). Однако, если эти комментарии не являются критическими, я бы либо отпустил их, либо, возможно, рассмотрел бы возможность их встраивания в качестве (хотя и избыточных) элементов данных.

...