配置就是一个装配数据字典的过程,一个字典也就是一个键值对,所以从配置就是键值对。
在asp.net core中关于配置是由四个基本的类型来支撑的,是①IConfigurationSource②IConfigurationProvider③IConfigurationBuilder④IConfiguration。
最终我们在程序中使用的是IConfiguration这个类型来获取配置中存入的信息,其他三个类型都是在asp.net core的启动过程中来帮助完成这个IConfiguration类型的。IConfigurationRoot这个接口继承IConfiguration接口,可以看作是一个东西(我现在的只是水平)。
具体过程是这样的:
IConfigurationBuilder这个类有一个Builder方法,在ICOnfigurationBuilder这个默认实现类ConfigurationBuilder:
public class ConfigurationBuilder : IConfigurationBuilder { /// <summary> /// Returns the sources used to obtain configuration values. /// </summary> public IList<IConfigurationSource> Sources { get; } = (IList<IConfigurationSource>) new List<IConfigurationSource>(); /// <summary> /// Gets a key/value collection that can be used to share data between the <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" /> /// and the registered <see cref="T:Microsoft.Extensions.Configuration.IConfigurationProvider" />s. /// </summary> public IDictionary<string, object> Properties { get; } = (IDictionary<string, object>) new Dictionary<string, object>(); /// <summary>Adds a new configuration source.</summary> /// <param name="source">The configuration source to add.</param> /// <returns>The same <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" />.</returns> public IConfigurationBuilder Add(IConfigurationSource source) { if (source == null) throw new ArgumentNullException(nameof (source)); this.Sources.Add(source); return (IConfigurationBuilder) this; } /// <summary> /// Builds an <see cref="T:Microsoft.Extensions.Configuration.IConfiguration" /> with keys and values from the set of providers registered in /// <see cref="P:Microsoft.Extensions.Configuration.ConfigurationBuilder.Sources" />. /// </summary> /// <returns>An <see cref="T:Microsoft.Extensions.Configuration.IConfigurationRoot" /> with keys and values from the registered providers.</returns> public IConfigurationRoot Build() { List<IConfigurationProvider> configurationProviderList = new List<IConfigurationProvider>(); foreach (IConfigurationSource source in (IEnumerable<IConfigurationSource>) this.Sources) { IConfigurationProvider configurationProvider = source.Build((IConfigurationBuilder) this); configurationProviderList.Add(configurationProvider); } return (IConfigurationRoot) new ConfigurationRoot((IList<IConfigurationProvider>) configurationProviderList); } }
有两个关键的地方比较重要:
一个是:
public IList<IConfigurationSource> Sources { get; } = (IList<IConfigurationSource>) new List<IConfigurationSource>();
这个list维护一个IConfigurationSource的集合,IConfigurationSource有一个Build方法来生成IConfigurationProvider,后面再说。
另一个是:
public IConfigurationRoot Build() { List<IConfigurationProvider> configurationProviderList = new List<IConfigurationProvider>(); foreach (IConfigurationSource source in (IEnumerable<IConfigurationSource>) this.Sources) { IConfigurationProvider configurationProvider = source.Build((IConfigurationBuilder) this); configurationProviderList.Add(configurationProvider); } return (IConfigurationRoot) new ConfigurationRoot((IList<IConfigurationProvider>) configurationProviderList); }
Build方法最终就是产生一个IConfigurationRoot类型。看一下里面的构造:
首先定义一个List装IConfigurationProvider的集合,然后遍历source集合,在遍历的逻辑内部将每一个IConfigurationSource转换为ConfigurationProvider之后装入这个IConfigurationProvider的list中,最后,再用这个list去初始化一个IConfigurationRoot。到此,我们就可以用DI来获取这个类型来找到我们想要的配置项了。
需要注意的是不同的配置源都有相应的类型的IConfigurationSource和IConfigurationProvider,比如:JsonConfigurationProvider和JsonConfigurationSource,这两个是用来配置json数据配置文件的,还有关于命令行的,环境变量的,等等,都是类似的,在学习源码的时候,多看一下就是了。