如何使用.NET配置文件(app.config、settings.settings)保存和恢复所有应用程序数据?

发布于 2024-08-14 09:25:26 字数 1212 浏览 2 评论 0 原文

尽管有很多关于 .net 配置文件的帖子,但我相信我的要求不允许提出任何建议的解决方案(或者我对这个过程的理解不足以使其适合我)。

情况是,我有一个 Windows 窗体应用程序(也可以是另一个应用程序),它将某些用户输入字段(例如 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)

但我不知道如何将当前配置中的所有设置完全替换为导入文件的设置。 [编辑:此重载应该接收 .exe 的路径,而不是 .config 文件。如果调用代码没有引用配置文件中的相同程序集,以这种方式打开 exe 文件可能会引发 ConfigurationErrorsException。]

也许我只需要使用 其他帖子仅替换配置的一部分,而不是整个配置,但我没有看到此时这将如何运作。

有什么想法吗?我是否走在正确的轨道上,或者我应该只使用 INI 文件(或其他文件)?

Although there are a lot of posts about .net config files, I believe that my requirements do not allow for any of the solutions proposed (or I don't understand the process enough to make it work for me).

The situation is that I have a Windows Forms application (could just as well be another app) which binds certain user input fields (e.g. IP Address), as well as form properties (window size, etc) to application settings (in the Properties->Settings area). From what I understand, these settings are the same as those represented in my project's app.config file, so I should be able to use the System.Configuration.ConfigurationManager class to manipulate those settings.

What I want to do is to allow the user to export and import all of the saved settings. Rather than doing serialization of some custom object or working with INI files, I thought it would be easier to just save and replace the config file that the application uses.

It is relatively easy to save the current settings to a specified file:

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

However, restoring a config file to overwrite the current settings is proving difficult. It seems like I can open a configuration file like so

var newConfig = ConfigurationManager.OpenExeConfiguration(settingsFilePath)

but I don't see how to completely replace all of the settings in the current config with those of the imported file. [Edit: This overload is supposed to receive the path of the .exe, not the .config file. Opening an exe file in this manner will possibly throw a ConfigurationErrorsException if the calling code doesn't reference the same assemblies in the config file.]

Perhaps I only need to use the methods outlined in other posts to replace only a section of the config, and not the whole thing, but I don't see how that would work at this point.

Any ideas? Am I going down the right track, or should I just use INI files (or something else)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

泪冰清 2024-08-21 09:25:26

最佳实践是不要写入 app.config,而是使用设置文件来保存修改的用户设置。 app.config 和 web.config 只能用于只读值。

It is best practice to NOT write to the app.config but use the settings file for saving user settings that are modified. The app.config and web.config should only be used for read only values.

榕城若虚 2024-08-21 09:25:26

由于您的 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");

我根据 @Pat 的评论更正了 XDocument.Load() 代码

Since you app.config file is a simple xml file you can load it into an XDocument:

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

I corrected the XDocument.Load() code according to @Pat's comment

冰之心 2024-08-21 09:25:26

由于我没有收到任何其他答案,并且对之前的解决方案不满意,因此我再次提出问题,做了更多研究,并能够提出更好的答案。请参阅如何加载单独的应用程序设置文件动态并与当前设置合并? 获取代码和说明。

Since I did not receive any other answers and was not happy with my previous solution, I asked the question again, did some more research, and was able to come up with a better answer. See How to load a separate Application Settings file dynamically and merge with current settings? for the code and explanation.

ˇ宁静的妩媚 2024-08-21 09:25:26

我认为覆盖整个配置文件不是一个好主意。此文件中的某些设置可能包含要在您的任何代码有机会执行任何操作(即与 .NET CLR 启动相关的操作)之前尽早处理的设置。

I do not think overriding the entire config file is a good idea. Some of the settings in this file might contain settings to be processed really early, before any of your code had a chance to do anything i.e. the ones related to the startup of .NET CLR.

云仙小弟 2024-08-21 09:25:26

感谢 Manu 建议将文件读取为 XML,我一起编写了 此解决方案。 (它仅适用于保存为字符串的属性的当前表单,例如 TextBox 的 Text 属性。例如,如果保留 NumericUpDown 控件的 Value 属性,则它不起作用。)它通过使用 Export 来工作要保存的文件的路径,这会生成如下所示的文件:

<?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);
        }
    }
}

Thanks to Manu's suggestion to just read the file as XML, I hacked together this solution. (It only works in the current form for properties saved as strings, such as the Text property of a TextBox. It won't work, for instance, if you persist the Value property of a NumericUpDown control.) It works by using Export with a path to the file to save, which produces a file like the following:

<?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>

Then you Import the file and all of the settings are changed in the app (don't forget to .Save() at some point). If something goes wrong, the settings will revert back.

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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文