在运行时从不同的文件加载 Properties.Settings [英] Loading Properties.Settings from a different file at runtime

查看:36
本文介绍了在运行时从不同的文件加载 Properties.Settings的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法在运行时从默认 App.config 文件以外的其他文件加载设置?我想在加载默认配置文件后执行此操作.

Is there any way to load settings from a different file other than the default App.config file at runtime? I'd like to do this after the default config file is loaded.

我使用 Visual Studio 中的 Settings.Settings GUI 为我创建我的 App.config 文件.配置文件最终看起来像这样:

I use the Settings.Settings GUI in Visual Studio to create my App.config file for me. The config file ends up looking like this:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <configSections>
            <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="SnipetTester.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
    </configSections>
      <applicationSettings>
        <SnipetTester.Properties.Settings>
          <setting name="SettingSomething" serializeAs="String">
            <value>1234</value>
          </setting>
        </SnipetTester.Properties.Settings>
      </applicationSettings>
    </configuration>

在代码中,我可以访问这样的设置:

In code, I'm able to access the settings like this:

Console.WriteLine("Default setting value:  " + Properties.Settings.Default.SettingSomething);

这个想法是,当应用程序运行时,我应该能够在运行时指定一个配置文件,并让应用程序将配置文件加载到 Properties.Settings.Default 对象而不是使用默认的 app.config 文件.配置文件的格式相同,但设置的值不同.

The idea is that when the application is run, I should be able to specify a config file at run time and have the application load the config file into the Properties.Settings.Default object instead of using the default app.config file. The formats of the config files would be the same, but the values of the settings would be different.

我知道一种使用 ConfigurationManager.OpenExeConfiguration(configFile); 做到这一点的方法.但是,在我运行的测试中,它不会更新 Properties.Settings.Default 对象以反映配置文件中的新值.

I know of a way to do this with the ConfigurationManager.OpenExeConfiguration(configFile);. However, in the tests that I've run, it doesn't update the Properties.Settings.Default object to reflect the new values from the config file.

在考虑了一段时间之后,我已经能够想出一个我更喜欢的解决方案.我确定它有一些缺陷,但我认为它可以满足我的需求.

After thinking about this a bit longer, I've been able to come up with a solution that I like a little better. I'm sure it has some pitfalls, but I think it'll work for what I need it to do.

本质上,Properties.Settings 类是由 Visual Studio 自动生成的;它为您生成类的代码.我能够找到生成代码的位置并添加一些函数调用来自行加载配置文件.这是我的补充:

Essentially, the Properties.Settings class is automatically generated by Visual Studio; it generates the code for the class for you. I was able to find where the code was generated and add a few function calls to load a config file on its own. Here's my addition:

internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 
{
    //Parses a config file and loads its settings
    public void Load(string filename)
    {
        System.Xml.Linq.XElement xml = null;
        try
        {
            string text = System.IO.File.ReadAllText(filename);
            xml = System.Xml.Linq.XElement.Parse(text);
        }
        catch
        {
            //Pokemon catch statement (gotta catch 'em all)

            //If some exception occurs while loading the file,
            //assume either the file was unable to be read or
            //the config file is not in the right format.
            //The xml variable will be null and none of the
            //settings will be loaded.
        }

        if(xml != null)
        {
            foreach(System.Xml.Linq.XElement currentElement in xml.Elements())
            {
                switch (currentElement.Name.LocalName)
                {
                    case "userSettings":
                    case "applicationSettings":
                        foreach (System.Xml.Linq.XElement settingNamespace in currentElement.Elements())
                        {
                            if (settingNamespace.Name.LocalName == "SnipetTester.Properties.Settings")
                            {
                                foreach (System.Xml.Linq.XElement setting in settingNamespace.Elements())
                                {
                                    LoadSetting(setting);
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }

    //Loads a setting based on it's xml representation in the config file
    private void LoadSetting(System.Xml.Linq.XElement setting)
    {
        string name = null, type = null, value = null;

        if (setting.Name.LocalName == "setting")
        {
            System.Xml.Linq.XAttribute xName = setting.Attribute("name");
            if (xName != null)
            {
                name = xName.Value;
            }

            System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs");
            if (xSerialize != null)
            {
                type = xSerialize.Value;
            }

            System.Xml.Linq.XElement xValue = setting.Element("value");
            if (xValue != null)
            {
                value = xValue.Value;
            }
        }


        if (string.IsNullOrEmpty(name) == false &&
            string.IsNullOrEmpty(type) == false &&
            string.IsNullOrEmpty(value) == false)
        {
            switch (name)
            {
                //One of the pitfalls is that everytime you add a new
                //setting to the config file, you will need to add another
                //case to the switch statement.
                case "SettingSomething":
                    this[name] = value;
                    break;
                default:
                    break;
            }
        }
    }
}

我添加的代码公开了一个 Properties.Settings.Load(string filename) 函数.该函数接受一个配置文件名作为参数.它将解析文件并加载它在配置文件中遇到的任何设置.要恢复到原始配置,只需调用 Properties.Settings.Reload().

The code I added exposes an Properties.Settings.Load(string filename) function. The function accepts a config filename as a parameter. It will parse the file and load up any settings it encounters in the config file. To revert back to the original configuration, simply call Properties.Settings.Reload().

希望这可以帮助其他人!

Hope this might help someone else!

推荐答案

这取决于应用程序的类型:

It depends on the type of the application:

  1. Web 应用程序和Windows 应用程序 - 使用 configSource xml 属性,如果您愿意将配置文件存储在与应用程序相同的文件夹(或子文件夹)中
  2. 创建一个 settings provider 并实施 IApplicationSettingsProvider.示例 此处此处.您可能还需要使用 IConfigurationManagerInternal 接口替换默认的 .NET 配置管理器.在实施提供商时,不要忘记区分用户设置和应用程序设置以及漫游配置文件.
  1. Web Application & Windows Application - use the configSource xml attribute if you are willing to store the config files in the same folder (or subfolders) as the application
  2. Create a settings provider and also implement IApplicationSettingsProvider. Samples here and here. You might also need to use the IConfigurationManagerInternal interface to replace the default .NET configuration manager. When implementing the provider don't forget to make a difference between user settings and application settings and the roaming profiles.

如果您想快速入门,只需反编译 LocalFileSettingsProvider 类(默认设置提供程序)并将其更改为您的需要(您可能会发现一些有用的代码,并且可能需要复制它所依赖的所有类).

If you want to get started quickly just decompile the LocalFileSettingsProvider class (the default settings provider) and change it to your needs (you might find some useles code and might need to replicate all of the classes on which it depends).

祝你好运

这篇关于在运行时从不同的文件加载 Properties.Settings的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆