这棵由ConfigurationRoo对象表示的配置树其实是无状态的,也就说不论是ConfigurationRoot对象还是ConfigurationSection对象,它们并没有利用某个字段存储任何的配置数据 接下来我们从ConfigurationRoot和ConfigurationSection这两个类型的定义来对这个数据流,以及建立在此基础上的配置同步机制作进一步的介绍,不过在这之前我们得先来了解一个名为 四、ConfigurationSection对象 如下所示的代码片段大体上体现了代表配置节的ConfigurationSection类型的实现逻辑。 如下面的代码片段所示,一个ConfigurationSection对象通过代表配置树根的ConfigurationRoot对象和当前配置节在配置树中的路径来构建。 ConfigurationSection的Path属性直接返回构建时指定的路径,而Key属性则由根据这个路径解析出来 。
如右图所示,一棵完整的配置树由一个ConfigurationRoot对象和若干ConfigurationSection构成。 我们将所有实现了IConfigurationSection接口的类型及其对象统称为ConfigurationSection,一个ConfigurationSection对应着配置树中某个非根配置节。 它的GetChildren方法返回一组表示其子配置节的ConfigurationSection对象集合,另一个方法GetSection则根据指定的Key返回对应的ConfigurationSection 当GetSection方法执行的时候,指定的参数将会与当前ConfigurationSection的Path进行组合以确定目标ConfigurationSection所在的路径,所以如果在调用该方法的时候指定一个相对于当前配置节的路径 ConfigurationSection 在上面关于用于模拟ConfigurationRoot类型定义的代码中我们知道最终表示非根配置节的ConfigurationSection对象是根据它的路径和作为根配置节的
下图为我们展示了由一个ConfigurationRoot对象和一组 ConfigurationSection对象构成的配置树。 ? 对象,而Path则表示当前配置节点在配置树中的路径,该路径由ConfigurationSection的Key组成,并采用冒号(“:”)作为分隔符。 在大部分情况下,只有配置树的叶子节点对应的ConfigurationSection对象才具有值,非叶子节点对应的ConfigurationSection对象实际上仅仅表示存放所有子配置节点的逻辑容器,它们的 上面这段代码还体现了另一个有趣的现象,虽然这三个ConfigurationSection对象均指向配置树的同一个节点,但是它们却并非同一个对象。 后面提到的ConfigurationRoot和ConfigurationSection也是这样,请读者朋友注意区分。
项目中自定义了一个配置节(ConfigurationSection),作为模拟,我们定义了如下一个简单TestConfigurationSection类。 TestConfigurationSection继承自ConfigurationSection,具有唯一的一个必需(IsRequired=true)配置属性Type,我们在这里设置一个类型的有效名称。 1: public class TestConfigurationSection : ConfigurationSection 2: { 3: [ConfigurationProperty ConfigurationManager.GetSection方法也会真正返回一个对应的类型的ConfigurationSection对象。 在这种情况下,配置元素的默认值(通过ConfigurationPropertyAttribute的DefaultValue属性定义)会反映在该ConfigurationSection对象上,所以不会有什么问题
方法2:
继承ConfigurationSection类,配合ConfigurationProperty特性来实现
public class ObjectContainerElement : ConfigurationElement }
///
"openid", "profile", "role", "phone", "address" }; var configurationSection = _configuration.GetSection("IdentityServer:Clients"); foreach (var section in configurationSection.GetChildren
ConfigurationRoot还有一个GetSection方法,会返回一个IConfigurationSection对象,对应的是ConfigurationSection类。 它的代码如下: public class ConfigurationSection : IConfigurationSection { private readonly ConfigurationRoot _root; private readonly string _path; private string _key; public ConfigurationSection 所以ConfigurationRoot和ConfigurationSection就像一个外壳,自身并不负责数据源的加载(或重载)与存储,只负责构建了一个配置值的读取功能。 而由于配置值的读取是按照数据源加载顺序的倒序进行的,所以对于Key值相同的多个配置,只会读取后加载的数据源中的配置,那么ConfigurationRoot和ConfigurationSection就模拟出了一个树状结构
(key, value); } } } GetSection public IConfigurationSection GetSection(string key) { return new ConfigurationSection (this, key); } public class ConfigurationSection : IConfigurationSection, IConfiguration { private (Path, key)]; } set { _root[ConfigurationPath.Combine(Path, key)] = value; } } public ConfigurationSection public IChangeToken GetReloadToken() { return _root.GetReloadToken(); } } 可以看到GetSection会生成一个ConfigurationSection 对象 而ConfigurationSection在读取/设置值时实际上就是对查询的Key用:拼接,然后调用IConfigurationRoot(_root)的赋值或查询函数 关于Configuration
由于ConfigurationRoot、ConfigurationSection聚集于IConfiguration接口,此处也对这两个类进行讨论,方便我们对.NET Core的配置功能有个更加形象的印象 前面有ConfigurationRoot表示配置的根节点,那么ConfigurationSection则表示非跟节点,毕竟父节点、子节点都是相对,所以此处使用非根节点。 ConfigurationSection继承于IConfigurationSection,该接口只有三个只读属性,分别表示配置信息的Key、Value以及路径信息,需要指出的是,此处的路径信息主要指从根节点到当前节点的路径 ,以表示当前节点的位置,类似于A:B:C可以表示节点C的位置,其中A、B、C都是ConfigurationSection的Key。 以下是ConfigurationSection的源码
1: ///
使用步骤: 1.先定义希望序列化保存的类,注意要继承自ConfigurationSection,示例代码如下: Code using System.Configuration; namespace ConfigTest { public class MyConfigClass : ConfigurationSection { [ConfigurationProperty("name")]
其二,继承ConfigurationSection,这种方法就简单多了,只需要指定对应的属性名称即可。 System.Configuration; using System; namespace SampleWebConfigSection.Configuration { public class customSection : ConfigurationSection System.Configuration; namespace SampleWebConfigSection.Configuration { public class webSettingSection : ConfigurationSection fileUploadSection FileUploadSetting { get { return (fileUploadSection)base["fileUpload"]; } } } } 派生自ConfigurationSection ------------------------------------------------- ps.补充一点Configuration自定义节点结构: ConfigurationSection:对应整个自定义节点
实现代码如下: namespace Demo { public class Section1 : ConfigurationSection { [ConfigurationProperty ="123456"></Users> </Test2> </configuration> 实现代码如下: namespace Demo { public class Section2 : ConfigurationSection ]]> </T2> </Test3> </configuration> 代码实现如下: namespace Demo { public class Section3 : ConfigurationSection 在创建ConfigurationSection的继承类时,创建一个表示集合的属性就可以了,注意[ConfigurationProperty]的各参数。 实现代码如下: namespace Demo { public class Section4 : ConfigurationSection { private static
} 8: public bool HasChanged { get; } 9: } 对于实现了IConfiguration接口的两个默认类型(ConfigurationRoot和ConfigurationSection ConfigurationRoot和ConfigurationSection这两个类型分别采用如下的形式实现了GetReloadToken方法。 我们从给出的代码片段不难看出所有的ConfigurationSection对象和作为它们根的ConfigurationRoot对象来说,它们的GetReloadToken方法在同一时刻返回的是同一个ConfigurationReloadToken ConfigurationReloadToken()).OnReload(); 15: } 16: //其他成员 17: } 18: 19: public class ConfigurationSection
在 OpenIddictDataSeedContributor 中增加新的客户端 // WeChat MiniProgram var weChatMiniProgramClientId = configurationSection OpenIddictConstants.ConsentTypes.Implicit, displayName: "WeChat Mini-program", secret: configurationSection
ConfigurationManager.AppSettings["key"]; 资源设置 用户,在系统缓存中备份,同时修改配置文件才可以 应用程序,单文件存储 Properties.Settings访问 configsections xml节点:ConfigurationSection
实现代码如下: namespace Demo { public class Section1 : ConfigurationSection { [ConfigurationProperty ="123456"></Users> </Test2> </configuration> 实现代码如下: namespace Demo { public class Section2 : ConfigurationSection ]]> </T2> </Test3> </configuration> 代码实现如下: namespace Demo { public class Section3 : ConfigurationSection 在创建ConfigurationSection的继承类时,创建一个表示集合的属性就可以了,注意[ConfigurationProperty]的各参数。 实现代码如下: namespace Demo { public class Section4 : ConfigurationSection { private static
SectionInformation 获取一个 SectionInformation 对象,该对象包含 ConfigurationSection 对象的不可自定义的信息和功能。 (从 ConfigurationSection 继承。)
Ninesky.Core.Config
{
///
如果绑定的目标类型为简单类型,在进行配置绑定的时候自需要将配置项的值(体现为ConfigurationSection的Value属性)转换成对应的数据类型就可以了。 我们利用这个ConfigurationBuilder对象创建的Configuration对象并调用这个ConfigurationSection的Get方法将Key为“Profile”的配置节绑定为一个Profile 我们利用这个ConfigurationBuilder对象创建的Configuration对象并调用这个ConfigurationSection的Get方法将Key为“Profiles”的配置节绑定为一个 我们利用这个ConfigurationBuilder对象创建的Configuration对象并调用这个ConfigurationSection的Get方法将Key为“Profiles”的配置节绑定为一个
Configer
{
///