简体   繁体   English

在 .NET 中在运行时合并自定义配置部分

[英]Merging custom configuration sections at runtime in .NET

My question is about working with standard .NET configuration objects and custom configuration elements as well, (which one can define by extending the System.Configuration.ConfigurationSection class).我的问题是关于使用标准 .NET 配置对象和自定义配置元素(可以通过扩展System.Configuration.ConfigurationSection类来定义)。 We usually obtain these from the System.Configuration.ConfigurationManager class's methods, GetSection(...) being an example.我们通常从System.Configuration.ConfigurationManager类的方法中获取这些,例如GetSection(...)

The loaded configuration object appears to be a merged configuration object containing the setup present in the application config file (the the app.config or web.config file which a developer may have created) and what is defined in the machine.config file (the latter coming with the .NET Framework installation).加载的配置对象似乎是一个合并的配置对象,其中包含应用程序配置文件(开发人员可能创建的app.configweb.config文件)中存在的设置以及machine.config文件中定义的内容(后者随 .NET Framework 安装一起提供)。

So, we can assume that the configuration is loaded in hierarchical manner with the machine.config first, and any user-defined configuration overlaying that default setup, and could be looked at like this:因此,我们可以假设配置首先使用machine.config以分层方式加载,并且任何用户定义的配置覆盖该默认设置,并且可以如下所示:

  • machine.config机器配置文件
    • app.config (overrides / merges with respective elements found in machine.config ) app.config (覆盖/合并与 machine.config 中的相应元素)

My goal is to create multiple layers of configuration, so that there might be other config files between (and if possible, after) the machine.config and the app.config file:我的目标是创建多层配置,以便在machine.configapp.config文件之间(如果可能的话,在之后)可能有其他配置文件:

  • machine.config机器配置文件
    • custom.config (a custom config interfering between the machine.config and the app.config file) custom.config (干扰 machine.config 和 app.config 文件的自定义配置)
      • app.config - now app.config is merged with both machine.config and custom.config app.config - 现在app.configmachine.configcustom.config合并

Update更新

The point with that is - if I have defined the configuration section in both custom.config and app.config , I need to get a merged version of both configs when I call ConfigurationManager.GetSection("MyCustomSection") .重点是 - 如果我在custom.configapp.config中都定义了配置部分,则在调用ConfigurationManager.GetSection("MyCustomSection")时需要获得两个配置的合并版本。 Ideally, it will be great if I am able to perform merging as describe in this MSDN article .理想情况下,如果我能够按照这篇 MSDN 文章中的描述执行合并,那就太好了。


Normally, I would write my own configuration manager class and will try to get as far as I could to get the desired result, but assuming the .NET framework has this working for machine.config and app.config , I thought I might benefit from the built-in functionality of the framework.通常,我会编写自己的配置管理器类,并尽可能地获得所需的结果,但假设 .NET 框架可以为machine.configapp.config 工作,我想我可能会从中受益框架的内置功能。 In addition, I do not know how to manually trigger such merging, if I am indeed supposed to resort to a config manager implementation of my own.此外,我不知道如何手动触发这种合并,如果我确实应该求助于我自己的配置管理器实现。

So, is it possible to leverage the built-in mechanisms of configuration section/element merging with custom configuration files?那么,是否可以利用配置部分/元素与自定义配置文件合并的内置机制? I am especially interested in developing and supporting this for custom configuration sections.我对开发和支持自定义配置部分特别感兴趣。 The System.Configuration namespace contains base objects to build configuration section and elements, and those allow some settings related to the merging (like setting the appropriate ConfigurationElementCollectionType for example). System.Configuration命名空间包含用于构建配置部分和元素的基础对象,这些对象允许与合并相关的一些设置(例如设置适当的ConfigurationElementCollectionType )。 Are these related to only merging with machine.config (or multiple layers of web.config files in a web application), or is it possible to manually trigger the merging of pre-loaded config files?这些仅与machine.config (或 Web 应用程序中的多层web.config文件)合并有关,还是可以手动触发预加载配置文件的合并? I am trying to avoid having to support custom merging in any of my custom configuration objects and probably forget about supporting the existing settings from the System.Configuration...我试图避免在我的任何自定义配置对象中支持自定义合并,并且可能忘记支持 System.Configuration 中的现有设置...


Update更新

There is an important clarification to I'd like to make, in response to the existing answers and comments.为了回应现有的答案和评论,我想做出一个重要的澄清。 I am capable of loading the ConfigurationSection objects from the current application setup ( app.config / web.config ) and from a physical file that is my custom.config .我能够从当前应用程序设置 ( app.config / web.config ) 和我的custom.config物理文件加载ConfigurationSection对象。 I need to know if there is a chance to merge these objects without resorting to reflection and property-by-property comparison, by some built-in means in the framework.我需要知道是否有机会通过框架中的一些内置方法在不诉诸反射和逐个属性比较的情况下合并这些对象。


Note: I would appreciate better a solution that would work on .NET 3.0+.注意:我更希望有一个适用于 .NET 3.0+ 的解决方案。 Please add a note if your answer targets a higher version of the framework.如果您的答案针对更高版本的框架,请添加注释。

The .NET configuration system is not super flexible .NET 配置系统不是超级灵活

That comment nails it and explains why you've been looking for a long time and haven't found anything yet.该评论指出了这一点,并解释了为什么您已经寻找了很长时间但还没有找到任何东西。 Not all the .NET Framework parts are "good", System.Configuration deserves the spot on the far bottom.并非所有 .NET Framework 部分都是“好”的,System.Configuration 应该放在最底层。 It is ridiculously over-engineered for something that's ultimately a simple task but at the same time turned into something exceedingly inflexible.对于最终是一项简单任务但同时又变得非常不灵活的事情来说,它被过度设计得可笑。 Hard to reverse-engineer how this happened, I think it got paralyzed by security concerns.很难逆向工程这是如何发生的,我认为它因安全问题而瘫痪。 Somewhat understandable perhaps, commandeering a program with data is always a considerable risk.或许可以理解,征用带有数据的程序始终是一个相当大的风险。

The only extension point that I know about is writing your own SettingsProvider .我所知道的唯一扩展点是编写您自己的SettingsProvider The framework has only one for general usage, the LocalFileSettingProvider class.该框架只有一个用于一般用途的 LocalFileSettingProvider 类。 Also exceedingly inflexible, there isn't any way to alter its behavior.同样非常不灵活,没有任何方法可以改变它的行为。 There is a decent example available for a custom setting provider, the RegistrySettingsProvider sample demonstrates a provider that stores settings in the registry.有一个可用于自定义设置提供程序的不错示例, RegistrySettingsProvider 示例演示了一个将设置存储在注册表中的提供程序。 It can be a good starting point for writing your own.它可以是编写自己的一个很好的起点。

Not exactly what you have in mind perhaps, do scratch the idea that you can break into the layering inside System.Configuration.也许并不完全是您的想法,请记住您可以打破 System.Configuration 中的分层。

As silver has pointed out, a well configured ExeConfigurationFileMap could do the job, at a certain cost.正如Silver所指出的,配置良好的ExeConfigurationFileMap可以完成这项工作,但需要付出一定的代价。

I have taken his example and made a working version of it.我已经采取了他的例子并制作了它的工作版本。

Here are the two config files I have merged for my test purposes:以下是我为测试目的合并的两个配置文件:

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>

And I used the following code to test the merged setup:我使用以下代码来测试合并的设置:

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");

pros of this approach这种方法的优点

  • I get the built-in merging logic to work我让内置的合并逻辑工作
  • Works for older versions of .NET (tested on 3.5)适用于旧版本的 .NET(在 3.5 上测试)
  • No need for reflection or other black magic stuff to trigger the behavior.不需要反射或其他黑魔法来触发行为。

cons缺点

  • Not very sure, but by setting map.MachineConfigFilename = PathToCustomConfig;不是很确定,但是通过设置map.MachineConfigFilename = PathToCustomConfig; I assume I am removing any values that are set up by the real machine.config file.我假设我正在删除由真实machine.config文件设置的任何值。 This could be error-prone and should be avoided for web applications, as most of them rely on what's in the real machine.config这可能容易出错,对于 Web 应用程序应该避免,因为它们中的大多数依赖于真实machine.config
  • One needs to pass the location of the application configuration file, as it is no longer determined automatically.需要传递应用程序配置文件的位置,因为它不再自动确定。 Thus one needs to figure out how the app.config will be named when the code is compiled (usually AssemblyName.exe.config)因此需要弄清楚在编译代码时app.config将如何命名(通常是 AssemblyName.exe.config)
  • You can merge the contents of two only files that way.您可以通过这种方式合并两个唯一文件的内容。 If one needs a larger hierarchy, then this will not work well.如果需要更大的层次结构,那么这将无法正常工作。

I am still in the process of refining the technique, thus I will return to update this post once done.我仍在完善该技术的过程中,因此一旦完成,我将返回更新此帖子。

There are actually 3 levels of configuration inheritance by default: Machine, Exe and User (which can be Roaming or Local).默认情况下实际上有 3 个级别的配置继承:Machine、Exe 和 User(可以是 Roaming 或 Local)。 If you're loading the configuration files yourself you can use the ExeConfigurationFileMap class in combination with ConfigurationManager.OpenMappedExeConfiguration to load your own custom configuration hierarchy.如果您自己加载配置文件,您可以将ExeConfigurationFileMap类与ConfigurationManager.OpenMappedExeConfiguration结合使用来加载您自己的自定义配置层次结构。

I don't think you can change where the default paths are for the ConfigurationManager class with this, but you will get a Configuration element which can be used to get whatever sections from the loaded config hierarchy.我不认为您可以使用此更改 ConfigurationManager 类的默认路径的位置,但是您将获得一个 Configuration 元素,该元素可用于从加载的配置层次结构中获取任何部分。

If you check out the answer to How to read configSections it includes some notes on determining at what level sections were declared in the hierarchy (using SectionInformation)如果您查看如何阅读 configSections的答案,它包含一些关于确定在层次结构中声明的级别的部分的注释(使用 SectionInformation)

var localSections = cfg.Sections.Cast<ConfigurationSection>()
       .Where(s => s.SectionInformation.IsDeclared);

have a look on the following code that knows to load your configurations or the exe configuration.看看下面的代码,知道加载你的配置或 exe 配置。 once the following code will be clear to you you can customize the loading and the merging as you wish (loading it twice and overriding one with the other).一旦您清楚以下代码,您就可以根据需要自定义加载和合并(加载两次并用另一个覆盖一个)。

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

}

we may need to use the classes ConfigurationSection and ConfigurationProperty我们可能需要使用类 ConfigurationSection 和 ConfigurationProperty

Please refer below link for the details on the implementation https://blog.danskingdom.com/adding-and-accessing-custom-sections-in-your-c-app-config/有关实施的详细信息,请参阅以下链接https://blog.danskingdom.com/adding-and-accessing-custom-sections-in-your-c-app-config/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM