Как использовать конфигурационные файлы .NET(app.config, settings.settings) для сохранения и восстановления всех данных приложения?

Несмотря на то, что есть много сообщений о файлах конфигурации .net, я считаю, что мои требования не позволяют ни одного из предложенных решений (или я не понимаю процесс, достаточный для того, чтобы он работал у меня).

Ситуация заключается в том, что у меня есть приложение Windows Forms (может также быть другим приложением), которое связывает определенные пользовательские поля ввода (например, IP-адрес), а также свойства формы (размер окна и т.д.) с настройками приложения (в в области Свойства- > Настройки). Насколько я понимаю, эти параметры те же, что и в моем файле app.config проекта, поэтому я должен использовать класс System.Configuration.ConfigurationManager для управления этими настройками.

Что я хочу сделать, так это разрешить пользователю экспортировать и импортировать все сохраненные настройки. Вместо того, чтобы выполнять сериализацию какого-либо пользовательского объекта или работать с INI файлами, я подумал, что было бы проще просто сохранить и заменить файл конфигурации, который использует приложение.

Относительно легко сохранить текущие настройки в указанном файле:

internal static void Export(string settingsFilePath)
{
    var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
    config.SaveAs(settingsFilePath);
}

Однако восстановление файла конфигурации для перезаписывания текущих настроек оказывается затруднительным. Кажется, что я могу открыть файл конфигурации, например,

var newConfig = ConfigurationManager.OpenExeConfiguration(settingsFilePath)

но я не вижу, как полностью заменить все настройки в текущей конфигурации на файлы импортированного файла. [Edit: эта перегрузка должна получать путь к .exe, а не к .config файл. Открытие exe файла таким образом, возможно, приведет к исключению ConfigurationErrorsException, если вызывающий код не ссылается на те же сборки в файле конфигурации.]

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

Любые идеи? Я иду по правильному пути, или я должен просто использовать INI файлы (или что-то еще)?

Ответ 1

Поскольку я не получил никаких других ответов и не был доволен своим предыдущим решением, я снова задал вопрос, сделал еще несколько исследований и смог найти лучший ответ. См. Как загрузить отдельный файл параметров приложения динамически и слить с текущими настройками? для кода и объяснений.

Ответ 2

Поскольку файл app.config представляет собой простой XML файл, вы можете загрузить его в XDocument:

string path = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
XDocument doc = XDocument.Load(path);
//Do your modifications to section x
doc.Save(path);
ConfigurationManager.RefreshSection("x");

Я скорректировал код XDocument.Load() в соответствии с комментарием @Pat

Ответ 3

Лучше всего НЕ писать в app.config, но использовать файл настроек для сохранения пользовательских настроек, которые были изменены. Параметры app.config и web.config должны использоваться только для значений только для чтения.

Ответ 4

Я не думаю, что переопределение всего файла конфигурации - хорошая идея. Некоторые параметры в этом файле могут содержать параметры, которые будут обрабатываться на самом деле раньше, прежде чем какой-либо из ваших кодов мог бы сделать что-либо, то есть связанные с запуском .NET CLR.

Ответ 5

Благодаря предложению Ману просто прочитать файл как XML, я взломал это решение. (Он работает только в текущей форме для свойств, сохраненных в виде строк, таких как свойство Text для TextBox. Он не будет работать, например, если вы сохраняете свойство Value элемента управления NumericUpDown.) Он работает с использованием Export with путь к файлу для сохранения, который создает файл следующего вида:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <HawkConfigGUI.Properties.Settings>
            <setting name="FpgaFilePath" serializeAs="String">
                <value>testfpga</value>
            </setting>
            <setting name="FirmwareFilePath" serializeAs="String">
                <value>test</value>
            </setting>
        </HawkConfigGUI.Properties.Settings>
    </userSettings>
</configuration>

Затем вы импортируете файл и все настройки будут изменены в приложении (не забудьте в какой-то момент .Save()). Если что-то пойдет не так, настройки вернутся назад.

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using AedUtils;

namespace HawkConfigGUI
{
    public static class SettingsIO
    {
        private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

        internal static void Import(string settingsFilePath)
        {
            if (!File.Exists(settingsFilePath))
            {
                throw new FileNotFoundException();
            }

            var appSettings = Properties.Settings.Default;
            try
            {
                // Open settings file as XML
                var import = XDocument.Load(settingsFilePath);
                // Get the <setting> elements
                var settings = import.XPathSelectElements("//setting");
                foreach (var setting in settings)
                {
                    string name = setting.Attribute("name").Value;
                    string value = setting.XPathSelectElement("value").FirstNode.ToString();

                    try
                    {
                        appSettings[name] = value; // throws SettingsPropertyNotFoundException
                    }
                    catch (SettingsPropertyNotFoundException spnfe)
                    {
                        _logger.WarnException("An imported setting ({0}) did not match an existing setting.".FormatString(name), spnfe);
                    }
                    catch (SettingsPropertyWrongTypeException typeException)
                    {
                        _logger.WarnException(string.Empty, typeException);
                    }
                }
            }
            catch (Exception exc)
            {
                _logger.ErrorException("Could not import settings.", exc);
                appSettings.Reload(); // from last set saved, not defaults
            }
        }

        internal static void Export(string settingsFilePath)
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            config.SaveAs(settingsFilePath);
        }
    }
}