【问题标题】:Loading Properties.Settings from a different file at runtime在运行时从不同的文件加载 Properties.Settings
【发布时间】:2012-07-28 11:37:23
【问题描述】:

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

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

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

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

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

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

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


在考虑了一段时间之后,我能够想出一个我更喜欢的解决方案。我敢肯定它有一些陷阱,但我认为它可以满足我的需要。

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

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()

希望这对其他人有帮助!

【问题讨论】:

  • 这看起来很有希望,但是我们如何使用这些类型

标签: c# app-config


【解决方案1】:

看看使用 ExeConfigurationFileMap 和 ConfigurationManager.OpenMappedExeConfiguration。

Cracking the Mysteries of .Net 2.0 Configuration

ExeConfigurationFileMap 允许您专门配置 机器、exe、漫游和本地配置的确切路径名 文件,一起,或零碎,调用时 OpenMappedExeConfiguration()。您不需要指定所有 文件,但所有文件将被识别并合并时 创建配置对象。使用时 OpenMappedExeConfiguration,重要的是要了解所有 通过您请求的级别的配置级别将始终 被合并。如果指定自定义 exe 和本地配置文件, 但不指定机器和漫游文件,默认机器和 漫游文件将被找到并与指定的exe和用户合并 文件。如果指定的文件,这可能会产生意想不到的后果 没有与默认文件正确同步。

【讨论】:

    【解决方案2】:

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

    1. Web 应用程序和 Windows 应用程序 - 如果您愿意将配置文件存储在与应用程序相同的文件夹(或子文件夹)中,请使用 configSource xml 属性
    2. 创建settings provider 并实现IApplicationSettingsProvider。示例 herehere。您可能还需要使用IConfigurationManagerInternal 接口来替换默认的.NET 配置管理器。在实施提供商时,不要忘记区分用户设置和应用程序设置以及漫游配置文件。

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

    祝你好运

    【讨论】:

      【解决方案3】:

      您可以包含类型,这样您就不需要每次都手动更新源。

      `private void LoadSetting(System.Xml.Linq.XElement 设置) { 字符串名称=空,类型=空; 字符串值 = 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)
                  {
                      if (this[name].GetType() == typeof(System.Collections.Specialized.StringCollection))
                      {
                          foreach (string s in xValue.Element("ArrayOfString").Elements())
                          {
                              if (!((System.Collections.Specialized.StringCollection)this[name]).Contains(s))
                                  ((System.Collections.Specialized.StringCollection)this[name]).Add(s);
                          }
                      }
                      else
                      {
                          value = xValue.Value;
                      }
      
                      if (this[name].GetType() == typeof(int))
                      {
                          this[name] = int.Parse(value);
                      }
                      else if (this[name].GetType() == typeof(bool))
                      {
                          this[name] = bool.Parse(value);
                      }
                      else
                      {
                          this[name] = value;
                      }
      
                  }
              }`
      

      【讨论】:

      • 是否可以对任意类型进行处理
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-27
      相关资源
      最近更新 更多