.net 如何动态加载单独的应用程序设置文件并与当前设置合并?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2389290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:02:11  来源:igfitidea点击:

How to load a separate Application Settings file dynamically and merge with current settings?

.netpersistenceconfiguration-filessettings

提问by Pat

There are questions pertaining to reading settings from a separate config fileand others similar to it, but my question is specific to application property settings (i.e. <MyApplication.Properties.Settings>- see XML file below) and how to load them dynamically. I tried the method in this post, which involved refreshing the entire appSettings section of the main config file, but my adaptation threw exceptions because I wasn't replacing the appSettings section:

存在与从单独的配置文件和其他类似配置文件读取设置有关的问题,但我的问题特定于应用程序属性设置(即<MyApplication.Properties.Settings>- 请参阅下面的 XML 文件)以及如何动态加载它们。我尝试了这篇文章中的方法,方法涉及刷新主配置文件的整个 appSettings 部分,但我的改编引发了异常,因为我没有替换 appSettings 部分:

var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
// Have tried the other ConfigurationUserLevels to no avail
config.AppSettings.File = myRuntimeConfigFilePath;
config.Save(ConfigurationSaveMode.Modified); // throws ConfigurationErrorsException
ConfigurationManager.RefreshSection("userSettings");

The ConfigurationErrorsException.Message is "The root element must match the name of the section referencing the file, 'appSettings' (C:\myFile.xml line 2)." The file is:

ConfigurationErrorsException.Message 是“根元素必须与引用文件‘appSettings’(C:\myFile.xml 第 2 行)的部分的名称相匹配。” 该文件是:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <MyApplication.Properties.Settings>
            <setting name="SineWaveFrequency" serializeAs="String">
                <value>6</value>
            </setting>
            <setting name="SineWaveAmplitude" serializeAs="String">
                <value>6</value>
            </setting>
        </MyApplication.Properties.Settings>
    </userSettings>
</configuration>

Is there a way to import the values from this file into the MyApplication.Properties.Settings.Defaultclass, with the framework handling all XML deserialization like it does when the config file is loaded on application startup?

有没有办法将值从这个文件导入到MyApplication.Properties.Settings.Default类中,框架会像在应用程序启动时加载配置文件一样处理所有 XML 反序列化?

采纳答案by Pat

Well, this works:

嗯,这有效:

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

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

        var appSettings = Properties.Settings.Default;
        try
        {
            var config = 
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);

            string appSettingsXmlName = 
Properties.Settings.Default.Context["GroupName"].ToString(); 
// returns "MyApplication.Properties.Settings";

            // Open settings file as XML
            var import = XDocument.Load(settingsFilePath);
            // Get the whole XML inside the settings node
            var settings = import.XPathSelectElements("//" + appSettingsXmlName);

            config.GetSectionGroup("userSettings")
                .Sections[appSettingsXmlName]
                .SectionInformation
                .SetRawXml(settings.Single().ToString());
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("userSettings");

            appSettings.Reload();
        }
        catch (Exception) // Should make this more specific
        {
            // Could not import settings.
            appSettings.Reload(); // from last set saved, not defaults
        }
    }

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

The export method creates a file like the following:

export 方法创建一个如下所示的文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <userSettings>
        <MyApplication.Properties.Settings>
            <setting name="SineWaveFrequency" serializeAs="String">
                <value>1</value>
            </setting>
            <setting name="SineWaveAmplitude" serializeAs="String">
                <value>100</value>
            </setting>
            <setting name="AdcShift" serializeAs="String">
                <value>8</value>
            </setting>
            <setting name="ControlBitsCheckedIndices" serializeAs="String">
                <value>0,1,2,3,5,6,7,8</value>
            </setting>
            <setting name="UpgradeSettings" serializeAs="String">
                <value>False</value>
            </setting>
        </MyApplication.Properties.Settings>
    </userSettings>
</configuration>

The import method parses that file, takes the everything inside the node, puts that XML into the user.config file at the appropriate section, then reloads the Properties.Settings.Default in order to grab those values from the new user.config file.

导入方法解析该文件,获取节点内的所有内容,将该 XML 放入 user.config 文件的适当部分,然后重新加载 Properties.Settings.Default 以从新的 user.config 文件中获取这些值。

回答by dhailis

The solution suggested by Pat:

Pat 建议的解决方案:

// Get the whole XML inside the settings node
var settings = import.XPathSelectElements("//" + appSettingsXmlName);

returns null. I changed it to

返回null。我把它改成

var settings = import.Element("configuration").Element("userSettings").Element(appSettingsXmlName);

config.GetSectionGroup("userSettings")
      .Sections[appSettingsXmlName]
      .SectionInformation
      .SetRawXml(settings.ToString());

And it works perfectly.

它完美地工作。