在运行时在.NET

时间:2015-05-04 10:45:08

标签: c# .net configuration configurationmanager

我的问题是关于使用标准.NET配置对象和自定义配置元素(可以通过扩展System.Configuration.ConfigurationSection类来定义)。我们通常从System.Configuration.ConfigurationManager类的方法中获取这些方法,GetSection(...)就是一个例子。

加载的配置对象似乎是合并的配置对象,其中包含应用程序配置文件中存在的设置( app.config web.config 开发人员可能已创建的文件)以及 machine.config 文件中定义的内容(后者随.NET Framework安装一起提供)。

因此,我们可以假设首先使用 machine.config 以分层方式加载配置,并且任何用户定义的配置都覆盖默认设置,并且可以像这样查看:< / p>

  • machine.config中
    • app.config (覆盖/合并在machine.config中找到的相应元素)

我的目标是创建多层配置,以便在 machine.config app.config 文件:

  • machine.config中
    • custom.config (自动配置干扰machine.config和app.config文件)
      • app.config - 现在 app.config machine.config custom.config 合并

更新

关键是 - 如果我在 custom.config app.config 中定义了配置部分,我需要获得两个配置的合并版本当我打电话给ConfigurationManager.GetSection("MyCustomSection")时。理想情况下,如果我能够按照this MSDN article中描述的那样执行合并,那将会很棒。

通常情况下,我会编写自己的配置管理器类,并尝试尽可能地获得所需的结果,但假设.NET框架适用于 machine.config 并且 app.config ,我想我可能会受益于框架的内置功能。另外,我不知道如何手动触发这样的合并,如果我确实应该采用我自己的配置管理器实现。

那么,是否可以利用配置部分/元素与自定义配置文件合并的内置机制?我特别感兴趣的是为自定义配置部分开发和支持它。 System.Configuration命名空间包含用于构建配置节和元素的基础对象,这些允许一些与合并相关的设置(例如设置相应的ConfigurationElementCollectionType)。这些是仅与 machine.config (或Web应用程序中的多个 web.config 文件层)合并,还是可以手动触发pre的合并加载配置文件?我试图避免在任何自定义配置对象中支持自定义合并,并且可能忘记支持System.Configuration中的现有设置......

更新

为了回应现有的答案和评论,我想做一个重要的澄清。我能够从当前的应用程序设置( app.config / web.config )和我ConfigurationSection个对象> custom.config 即可。我需要知道是否有机会合并这些对象,而不需要通过框架中的一些内置方法进行反射和逐个属性比较。

注意:我希望能更好地使用适用于.NET 3.0+的解决方案。如果您的答案针对更高版本的框架,请添加注释。

4 个答案:

答案 0 :(得分:8)

  

.NET配置系统不是超级灵活的

这条评论指出了它,并解释了为什么你一直在找很长时间而且还没找到任何东西。并非所有的.NET Framework部件都是“好”的,System.Configuration值得在最底层找到它。对于那些最终是一项简单任务但同时又变得非常不灵活的东西来说,这是荒谬的过度设计。很难对这种情况进行逆向工程,我认为因安全问题而陷入瘫痪。或许可以理解的是,用数据来征用一个程序总是存在相当大的风险。

我所知道的唯一延伸点是编写自己的SettingsProvider。该框架只有一个用于一般用途的LocalFileSettingProvider类。也非常不灵活,没有任何方法可以改变它的行为。有一个适用于自定义设置提供程序的示例,RegistrySettingsProvider sample演示了一个在注册表中存储设置的提供程序。这可以是写自己的好起点。

或许不完全是你的想法,请抓住你可以闯入System.Configuration内部分层的想法。

答案 1 :(得分:4)

正如silver指出的那样,配置良好的ExeConfigurationFileMap可以按一定的成本完成工作。

我已经采取了他的榜样并制作了一个可行的版本。

以下是我为测试目的合并的两个配置文件:

<强> custom.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="custom" type="..." />
  </configSections>
  <custom>
    <singleProperty id="main" value="BaseValue" />
    <propertyCollection>
      <property id="1" value="One" />
      <property id="4" value="Four" />
    </propertyCollection>
  </custom>
</configuration>

<强>的app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="custom" type="..."/>
  </configSections>
  <custom>
    <singleProperty id="main" value="OverriddenValue" />
    <propertyCollection>
      <property id="1" value="OverridenOne" />
      <property id="2" value="Two" />
      <property id="3" value="Three" />
    </propertyCollection>
  </custom>
</configuration>

我使用以下代码测试合并设置:

var map = new ExeConfigurationFileMap();
map.MachineConfigFilename = PathToCustomConfig;
map.ExeConfigFilename = PathToAppConfig;

var configuration = ConfigurationManager.OpenMappedExeConfiguration(
        map, 
        ConfigurationUserLevel.None);
var section = configuration.GetSection("custom") as CustomConfigSection;
Assert.IsNotNull(section);

Assert.AreEqual(section.SingleProperty.Value, "OverriddenValue");
Assert.AreEqual(section.PropertyCollection.Count, 4);
// Needed to map the properties as dictionary, not to rely on the property order
var values = section.PropertyCollection
        .Cast<SimpleConfigElement>()
        .ToDictionary(x => x.ID, x => x.Value);
Assert.AreEqual(values["1"], "OverridenOne");
Assert.AreEqual(values["2"], "Two");
Assert.AreEqual(values["3"], "Three");
Assert.AreEqual(values["4"], "Four");

这种方法的优点

  • 我得到了内置的合并逻辑
  • 适用于旧版本的.NET(在3.5上测试)
  • 不需要反射或其他黑魔法的东西来触发行为。

缺点

  • 不太确定,但通过设置map.MachineConfigFilename = PathToCustomConfig;我假设我删除了真实machine.config文件设置的任何值。这可能容易出错,应该避免使用Web应用程序,因为大多数都依赖于真实的machine.config
  • 中的内容。
  • 需要传递应用程序配置文件的位置,因为它不再自动确定。因此,需要弄清楚编译代码时如何命名app.config(通常是AssemblyName.exe.config)
  • 您可以合并两个文件的内容。如果需要更大的层次结构,那么这将无法正常工作。

我仍然在改进这项技术,因此我会在完成后返回更新这篇文章。

答案 2 :(得分:2)

查看以下代码,知道加载配置或exe配置。 一旦您清楚以下代码,您可以根据需要自定义加载和合并(加载两次并覆盖另一个)。

private static void InitConfiguration()
{
    var map = new ExeConfigurationFileMap();
    var AssemblyConfigFile = "";
    if (File.Exists(AssemblyConfigFile))
        map.ExeConfigFilename = AssemblyConfigFile;
    else
        map.ExeConfigFilename = Path.Combine(Environment.CurrentDirectory, Environment.GetCommandLineArgs()[0]+".config");

    var Configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

    var serviceModelSectionGroup = ServiceModelSectionGroup.GetSectionGroup(Configuration);

}

答案 3 :(得分:0)

我们可能需要使用这些类 ConfigurationSection和ConfigurationProperty

有关实现的详细信息,请参阅以下链接 https://blog.danskingdom.com/adding-and-accessing-custom-sections-in-your-c-app-config/