咱们以前写的配置都是放置在配置文件Web.config或者app.config中,.net core提供了全新的配置方式,能够直接写在内存中或者写在文件中。html
.Net Core的配置API主要体如今3个类中Configuration、ConfigurationBuilder、ConfigurationProvider中。json
配置文件其实就是一个键值对。Configuration以树形结构描述了这些键值对之间的关系。咱们的配置文件好比project.json是怎么转换成Configuration树形结构的呢?app
Microsoft.Extensions.Options这个命名空间下的类提供了文件向Configuration的转换。ide
1、配置文件分为3种结构ui
1. 逻辑结构:就是咱们看到的结构,树形结构。this
2. 原始结构:就是文件自己的结构,好比xml、json等等。spa
3. 物理结构:介于二者之间的结构,键值对。.net
配置组件的最终目的就是把原始结构转化成逻辑结构,在具体转换过程当中,先找到对应的ConfigurationProvider转化为物理结构数据字典,而后再由ConfigurationBuilder转化为逻辑结构Configuration对象。code
2、Configurationxml
Configuration对象泛指继承自接口IConfiguration的对象。这个接口以下:
namespace Microsoft.Extensions.Configuration { using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.Reflection; public interface IConfiguration { IEnumerable<IConfigurationSection> GetChildren(); IChangeToken GetReloadToken(); IConfigurationSection GetSection(string key); string this[string key] { get; set; } } }
这个接口GetChildren表示全部的ConfigurationSection对象;GetSection根据key值获得ConfigurationSection对象。
继承自这个接口的对象分别是ConfigurationRoot和ConfigurationSection,分别表示配置的根节点和叶子节点。
ConfigurationRoot还继承自接口IConfigurationRoot接口,代码以下:
namespace Microsoft.Extensions.Configuration { using System; public interface IConfigurationRoot : IConfiguration { void Reload(); } }
这个接口只有一个方法Reload从新加载,当调用这个方法的时候,在这棵树下的全部的节点都会从新加载。
ConfigurationSection还继承自IConfigurationSection,代码以下:
namespace Microsoft.Extensions.Configuration { using System; public interface IConfigurationSection : IConfiguration { string Key { get; } string Path { get; } string Value { get; set; } } }
Key表示父节点的名称;Path表示当前节点的路径,用“:”隔开;Value只有在叶子节点才有值,非叶子节点返回Null。
3、ConfigurationProvider
ConfigurationProvider对象泛指实现了接口IConfigurationProvider的对象。
namespace Microsoft.Extensions.Configuration { using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.Runtime.InteropServices; public interface IConfigurationProvider { IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath); IChangeToken GetReloadToken(); void Load(); void Set(string key, string value); bool TryGet(string key, out string value); } }
而继承自这个接口的是一个抽象类ConfigurationProvider,代码以下:
public abstract class ConfigurationProvider : IConfigurationProvider { // Fields private ConfigurationReloadToken _reloadToken; // Methods protected ConfigurationProvider(); public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath); public IChangeToken GetReloadToken(); public virtual void Load(); protected void OnReload(); private static string Segment(string key, int prefixLength); public virtual void Set(string key, string value); public virtual bool TryGet(string key, out string value); // Properties protected IDictionary<string, string> Data { get; set; } }
由于这个类的最终目的就是转化为数据字典,因此,这个类的方法大部分都是针对数据字典,方法的参数中都有key值。
不一样的数据源都是继承自这个抽象类,重写本身的方法。
Load方法从数据源加载数据,针对不一样的数据源子类能够重写;TryGet根据key值获取数据值;Set方法设置数据值,由于这个类的主要功能是从数据源读取数据转化为数据字典,因此Set的值只保存在内存中。
4、ConfigurationBuilder
泛指实现了接口IConfigurationBuilder的对象。他的做用就是根据ConfigurationProvider提供的数据字典,把数据字典转化为ConfigurationRoot对象。接口以下:
namespace Microsoft.Extensions.Configuration { using System.Collections.Generic; public interface IConfigurationBuilder { IConfigurationBuilder Add(IConfigurationSource source); IConfigurationRoot Build(); Dictionary<string, object> Properties { get; } IEnumerable<IConfigurationSource> Sources { get; } } }
主要经过Build方法实现把数据字典转化为ConfigurationRoot。
不管是ConfigurationRoot仍是ConfigurationSection自己都没有封装任何形式的对配置的读取操做,全部的读取操做都是在ConfigurationProvider对象中。
在ConfigurationRoot和ConfigurationSection组成的树形结构中,并无在代码中直接保存这种结构,而是每一个ConfigurationSection中都有一个ConfigurationRoot对象,直接是对根节点的引用。而只有根节点中有对ConfigurationProvider的调用。也就是在每一个叶子节点中都有一个对于根节点的引用。这样当咱们想要获取某个节点的具体值时,先找到根节点,再经过根节点找到ConfigurationProvider,经过ConfigurationProvider对象获取配置值。
还有一个对象ConfigurationPath,主要封装对树层级结构的计算,代码以下:
namespace Microsoft.Extensions.Configuration { using System; using System.Collections.Generic; public static class ConfigurationPath { public static readonly string KeyDelimiter = ":"; public static string Combine(IEnumerable<string> pathSegments) { if (pathSegments == null) { throw new ArgumentNullException("pathSegments"); } return string.Join(KeyDelimiter, pathSegments); } public static string Combine(params string[] pathSegments) { if (pathSegments == null) { throw new ArgumentNullException("pathSegments"); } return string.Join(KeyDelimiter, pathSegments); } public static string GetParentPath(string path) { if (!string.IsNullOrEmpty(path)) { int length = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase); if (length != -1) { return path.Substring(0, length); } } return null; } public static string GetSectionKey(string path) { if (!string.IsNullOrEmpty(path)) { int num = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase); if (num != -1) { return path.Substring(num + 1); } } return path; } } }
Combine方法实现把路径链接成一个完整的路径。
以上对象之间的关系图以下:
综上,配置模块的最终目的是要把原始的配置文件好比:json、xml转换为一个ConfigurationRoot对象,这个对象是一个树形结构,下边是ConfigurationSection对象。当咱们要获取某个配置时,经过ConfigurationRoot的ConfigurationProvider获取,每一个ConfigurationSection都有一个对于根节点的引用。
后记:当须要读取一个配置文件的时候,调用ConfigurationBuilder的build方法把文件内容转换为ConfigurationRoot对象,在这个方法执行过程当中,会调用根据配置文件的不一样调用相关的ConfigurationProvider ,而后调用ConfigurationProvider的Load方法,把配置文件转换成数据字典;而后再回到ConfigurationBuilder中把数据字典转化为ConfigurationRoot。
参考连接:http://www.cnblogs.com/artech/p/asp-net-core-config-01.html