配置选项代表两个独立的基础框架:
配置模型
.NET Core的配置在被应用程序消费的过程中是以 IConfiguration对象的形式来呈现的,因而将其称为配置树,配置树的称谓体现了其配置的逻辑结构。
配置的原始数据是多种多样的。配置模型的最终目的在于提取原始的配置数据并将其转换成一个 IConfiguration对象。
配置由原始结构如何转换为逻辑结构?
备注:
原始的配置数据被读取后会被转换为配置字典,之所以可以转换为配置字典是因为配置树的结构和承载的数据完全可以通过字典来表达,我们只需将配置树的路径当作key,将所承载的数据作为value即可。转换为配置字典后,再完成针对逻辑的转换。
IConfiguration
为什么说配置树是一种逻辑结构?
一个 IConfiguration对象具有树形层次结构并不是说对应的类型具有对应的数据成员定义,而是说它提供的 API 在逻辑上体现出树形层次结构,所以说配置树是一种逻辑结构。
根节点所在的 IConfiguration 对象体现为一个IConfigurationRoot 对象,其他节点对象则用一个 IConfigurationSection 对象来表示
key:唯一标识多个具有相同父节点的 ConfigurationSection对象
path:表示当前配置节点在配置树中的路径,由组成当前路径的所有IConfigurationSection对象的Key构成,Key之间采用冒号(:)作为分隔符
value:叶子节点有数据,非叶子节点返回null
Reload:实现对配置数据的重新加载,IConfigurationRoot 对象表示配置树的根,所以也代表了整棵配置树,如果它被重新加载,则意味着整棵配置树承载的所有配置数据均被重新加载
ConfigurationRoot对象保持着对所有注册的 IConfigurationSource对象提供的 IConfiguration Provider对象的引用,当调用 ConfigurationRoot对象或者 ConfigurationSection对象相应的 API提取配置数据时,最终都会直接从这些 IConfigurationProvider 对象中提取数据。换句话说,配置数据在整个模型中只以配置字典的形式存储在IConfigurationProvider对象上面。
IConfigurationProvider
虽然每种不同类型的配置源都有一个对应的 IConfigurationSource 实现,但是针对原始数据的读取并不是由它完成的,而是委托一个与之对应的 IConfigurationProvider 对象来实现
IConfigurationProvider 对象的目的在于将配置数据从原始结构转换成配置字典,所以定义在IConfigurationProvider接口中的方法大都体现为针对字典对象的操作
load:对配置数据的加载
set:设置的配置数据一般只是保存在内存中,不负责持久化更新后的配置数据
每种类型的配置源都对应一个 IConfigurationProvider 接口的实现类型,但它们一般不会直接实现 IConfigurationProvider接口,而是选择继承另一个名为 ConfigurationProvider的抽象类
IConfigurationSource
IConfigurationSource对象在配置模型中代表配置源,被注册到 IConfigurationBuilder对象上,为由它创建的 IConfiguration对象提供原始的配置数据。由于针对原始配置数据的读取在相应的IConfigurationProvider 对象中实现,所以 IConfigurationSource 对象的作用就在于提供相应的IConfigurationProvider对象
IConfigurationBuilder 对象利用注册在它上面的所有 IConfigurationSource对象提供的 IConfigurationProvider对象来读取原始配置数据并创建出相应的IConfiguration对象。
IConfigurationBuilder
IConfigurationBuilder 对象会利用注册的IConfigurationSource对象提供的原始数据创建供应用程序使用的 IConfiguration对象。
配置系统提供了一个名为 ConfigurationBuilder 的类作为 IConfigurationBuilder 接口的默认实现。ConfigurationBuilder 类型的 Build 方法返回一个类型为 ConfigurationRoot的对象,由它表示的配置树的每个非根配置节点均是一个类型为ConfigurationSection的对象。
配置模型的一个主要特点就是对多种配置源提供支持
配置源会被注册到IConfigurationBuilder对象上,由其提供相应的IConfigurationProvider对象,该对象负责读取配置源,将配置源转换为配置字典
MemoryConfigurationSource
InitialData:存放初始的配置数据
IConfigurationProvider对象在配置模型中所起的作用就是读取原始配置数据并将其转换成配置字典。
MemoryConfigurationProvider 定义的 Add 方法在任何时候都可以向配置字典中添加一个新的配置项。
EnvironmentVariablesConfigurationSource
环境变量的提取和维护可以通过静态类型Environment来完成
CommandLineConfigurationSource
CommandLineConfigurationSource 类型定义在 NuGet 包“Microsoft.Extensions.Configuration.CommandLine”中
CommandLineConfigurationSource 的根本目的在于将命名行开关从字符串数组转换成配置字典
FileConfigurationSource
物理文件是最常用的原始配置载体,主要有三种配置文件格式:json、xml、ini,对应的配置源类型分别是 JsonConfigurationSource、XmlConfigurationSource 和IniConfigurationSource,它们具有如下一个相同的基类FileConfigurationSource
IFileProvider 对象
读取配置文件,可以利用FileProvider属性来设置这个对象
path
配置文件的路径可以用 Path属性表示,一般来说这是一个针对 IFileProvider 对象根目录的相对路径
在读取配置文件时,这个路径将作为参数调用IFileProvider 对象的 GetFileInfo 方法,以得到描述配置文件的 IFileInfo 对象,该对象的CreateReadStream方法最终会被调用来读取文件内容
ResolveFileProvider
如果FileProvider 属性并没有被显式赋值,并且指定的配置文件路径是一个绝对路径(如“c:\app\appsettings.json”),那么将创建一个针对配置文件所在目录(“c:\app”)的 PhysicalFileProvider,并作为 FileProvider 的属性值,而 Path 属性将被设置成配置文件名。
EnsureDefaults
该方法会确保 FileConfigurationSource总是具有一个用于加载配置文件的 IFileProvider对象。具体来说,EnsureDefaults方法最终会调用IConfigurationBuilder接口具有如下定义的GetFileProvider扩展方法来获取默认的IFileProvider对象
//GetFileProvider 扩展方法实际上是将 IConfiguration Builder 对象的 Properties 属性表示的字典 //作为存放 IFileProvider 对象的容器(对应的 Key 为FileProvider)。 //如果这个容器中存在一个 IFileProvider 对象,那么它将作为方法的返回值。反之,该方法会将当前应用的 //基础目录(默认为当前应用程序域的基础目录,也就是当前执行的.exe文件所在的目录)作为根目录创建一个 //PhysicalFileProvider对象 public static class FileConfigurationExtensions { public static IFileProvider GetFileProvider(this IConfigurationBuilder builder) { if (builder.Properties.TryGetValue("FileProvider", out object provider)) { return builder.Properties["FileProvider"] as IFileProvider; } return new PhysicalFileProvider(AppContext.BaseDirectory ?? string.Empty); } }
Optional
表示当前配置源是否可以默认。如果该属性被设置成 False,即使指定的配置文件不存在也不会抛出异常
ReloadOnChange
是否监控文件系统,一般需要ReloadDelay属性配合使用,该属性的单位是毫秒,默认设置的延时为250毫秒。
StreamConfigurationSource
StreamConfigurationSource 对象通过指定的 Stream 对象来读取配置内容,所以这种配置源具有更加灵活的应用
ChainedConfigurationSource
自定义ConfigurationSource
配置绑定
配置绑定:将提取的配置数据转换成POCO对象,以面向对象的方式来使用配置的过程
配置绑定可以通过如下几个针对 IConfiguration的扩展方法来实现,这些扩展方法都定义在NuGet包“Microsoft.Extensions.Configuration.Binder”中。
所谓的配置绑定体现为如何将映射在配置树上某个节点的 IConfiguration对象(可以是 IConfigurationRoot对象或者 IConfigurationSection对象)转换成一个对应的POCO对象。
配置的同步
配置的同步涉及两个方面:
第一,对原始的配置源实施监控并在其发生变化之后重新加载配置;
第二,配置重新加载之后及时通知应用程序,进而使应用能够及时使用最新的配置
处于核心地位的 IConfiguration Builder对象,借助注册的 IConfigurationSource对象提供的 IConfigurationProvider对象,从相应的配置源中加载数据,而各种针对 IConfigurationProvider 接口的实现,就是为了将形态各异的原始配置数据转换成配置字典。
ConfigurationReloadToken
对于 IConfiguration接口的 GetReloadToken方法返回的 IChangeToken对象,其作用不是在配置源发生变化时向应用程序发送通知,而是通知应用程序:配置源已经发生改变,并且新的数据已经被相应的 IConfigurationProvider 对象重新加载进来
由于 Configuration Root 对象和 ConfigurationSection 对象都不维护任何数据,它们仅仅将 API 调用转移到IConfigurationProvider 对象上,所以应用程序使用原来的 IConfiguration 对象就可以获取最新的配置数据。
ConfigurationRoot
一个 ConfigurationRoot 对象是根据一组 IConfigurationProvider对象创建的,这些IConfigurationProvider对象则由注册的IConfigurationSource对象来提供。
GetReloadToken:
返回的是一个ConfigurationReloadToken对象,该对象用字段_changeToken 表示。如果需要利用这个对象对外发送配置重新加载的通知,就需要调用其 OnReload 方法。由于一个 IChangeToken 对象只能发送一次通知,所以该方法还负责创建新的 ConfigurationReload Token对象并对_changeToken字段赋值。
换句话说,一旦 ConfigurationRoot 的 RaiseChanged 方法被调用,我们就可以利用其GetReloadToken方法返回的 IChangeToken对象来接收配置被重新加载的通知。
如果多个 IConfigurationSource配置源提供的 IConfiguration Provider 对象包含同名的配置项,后面注册的 IConfigurationSource 对象就具有更高的选择优先级,我们应该根据这个特性合理安排 IConfigurationSource 对象的注册顺序