Может ли ConfigurationManager сохранять XML-комментарии к Save()?

Я написал небольшую утилиту, которая позволяет мне изменить простой 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 исходного файла конфигурации?

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


person Mike Atlas    schedule 23.12.2009    source источник
comment
У меня такая же проблема с .NET 4.0.   -  person pipelinecache    schedule 23.12.2009
comment
Также обнаружил, что это происходит только в разделе appSettings.   -  person pipelinecache    schedule 23.12.2009
comment
Комментарии также сохраняются в остальной части моего файла .config. Я обновил свой пост, чтобы отразить это.   -  person Mike Atlas    schedule 23.12.2009
comment
Возможно, чтобы сохранить комментарии, мне придется отредактировать файл конфигурации как обычный XmlDocument... см.: ryanfarley.com/blog/archive/2004/07/13/879.aspx   -  person Mike Atlas    schedule 23.12.2009
comment
Комментарии в разделе <connectionStrings> у меня тоже теряются v4.0   -  person DLeh    schedule 19.06.2014
comment
Спасибо, я просто удалил комментарии из раздела AppSettings, и все отлично работает.   -  person yossico    schedule 11.05.2015
comment
Проверьте ответ по ссылке ниже: https://stackoverflow.com/a/59215389/10148675   -  person Ruzo Owzy    schedule 06.12.2019


Ответы (3)


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

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

Прости. Это крайний случай, которого Microsoft просто не планировала.

person Mark Ewer    schedule 29.12.2009
comment
Я просто хотел бы сказать, что это Super Lame, что Microsoft не исправляет что-то подобное. Это не реальный мир. Комментарии не должны быть стерты. Я схожу с ума, когда технологическая компания не исправляет что-то настолько простое. - person John Cruz; 26.02.2020

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

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;
    }
}
person Kevin Green    schedule 13.11.2015
comment
Код не компилируется. Ошибки в этой строке: if(lastElement?.NodeType == System.Xml.XmlNodeType.Element && elm.NextNode?.NodeType == System.Xml.XmlNodeType.Comment) - person Ron Nuni; 08.12.2015
comment
?. — это новый стиль записи в VS2015 и .net 4.6. Он просто выполняет нулевую проверку перед получением свойства. Вы можете заменить это на: )) - person Kevin Green; 09.12.2015
comment
Прошло много времени с тех пор, как я написал C #, но проверки нулевых условий и добавления операторов объединения нулей, вероятно, были под влиянием синтаксического сахара других языков с динамической типизацией - может быть, в частности, из CoffeeScript? stackoverflow.com/q/6613952/101827 - person Mike Atlas; 30.12.2015

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

person Dmitri Nesteruk    schedule 27.12.2009