一, 配置简述
之前在. Net Framework 平台开发时, 一般配置文件都是 xml 格式的 web.config, 而需要配置其他格式的文件就需要自己去读取内容, 加载配置了.. 而 Net Core 支持从命令行, 环境变量, 文件, 内存, Key-per-file 中加载配置, 其中文件包括 xml,INI,JSON 三种文件格式. 这里需要说明一下, 不论哪种格式的配置文件, 加载到程序中最终会以 Key/Value 形式保存, 源码中将所有配置读取出来并保存在 Dictionary<string, string> Data 的字典中. 额外说明一下 Key-per-file 配置方式是以文件名称为 key, 文件内容为 value 的形式.
二, 源码解析
点击查看源码 https://github.com/aspnet/Configuration , 我画了一个主要类之间的逻辑关系图, 如下:
实线表示继承关系, 每条虚线表示意义已经在上面表明. 可以分为 4 个部分, 最终要构建的就是 IConfigurationRoot, 因为所有的配置都存储在它里面的 Providers 集合中的 Data 的字典中.
构建它两条路径, 一条通过 IConfigurationSource 构建 IConfigurationProvider, 然后通过 IConfigurationProvider 集合构建 IConfigurationRoot, 也就是图上标记的 1/2 两步.
另一条是通过 IConfigurationSource 集合构建 IConfigurationBuilder, 在通过 Builder 方法遍历循环创建创建 IConfigurationProvider 集合, 在通过 IConfigurationProvider 集合构建 IConfigurationRoot. 也就是图上的 3/4 两步.
这里只讲文件配置方式, 包括 xml,INI,JSON 文件.
IConfigurationSource:
它是配置文件的根本, 它表示配置文件本身, 比如继承自它的 FileConfigurationSource 里面有个 Path 属性, 表示文件路径, 会通过这个 Path 读取这个文件内容. 如我们常用的 xml,JSON,INI 文件配置都继承自 FileConfigurationSource .
IConfigurationProvider:
前面说了, 配置最终会转换为 key/value 的形式, 而 IConfigurationProvider 就是这个装换. 比如继承他的 FileConfigurationProvider , 它的构造函数需要传第一个 FileConfigurationSource , FileConfigurationProvider 会根据 FileConfigurationSource 的 path 属性找到对应文件, 然后读取配置文件到它的 IDictionary<string, string> Data 中. xml 的读取在 XmlConfigurationProvider 中, JSON 文件的读取在 JsonConfigurationProvider .
- private void Load(bool reload)
- {
- // 删除一些判断逻辑
- if (reload)
- {
- Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
- using (var stream = file.CreateReadStream())
- {
- // 这一步会将文件里面的配置 放到 Data 中 不同的文件格式 Load 方法都有对应的实现, 这里就不细看了.
- Load(stream);
- }
- OnReload();
- }
一个 IConfigurationProvider 的实现类中会包含一个对应的 IConfigurationSource 的实现类, 比如 JsonConfigurationProvider 类中包含一个 JsonConfigurationProvider
IConfigurationRoot:
所有的类最终构建的目标就是 IConfigurationRoot, 它包含一个 IList<IConfigurationProvider> _providers 集合, 而每一个 IConfigurationProvider 包含一个 IDictionary<string, string> Data , 所以现在你现在是不是有提花灌顶的感觉. 这样做的目的是一个程序可能有多个配置文件, 可能有一个 xml 文件, 一个 JSON 文件, 一个 INI 文件. 每个配置文件会被读取到对应的 ConfigurationSource 中, 然后通过它构建对应的 ConfigurationProvider , 然后用三个 ConfigurationProvider 构建 ConfigurationRoot .
那这样会有一个问题, 比如 xml 文件配置了 A 的值为 1,JSON 文件也配置名称为 A 的值为 2, 那会获取谁的值呢? 下面源码可以看到, IConfigurationRoot 会反转添加的顺序, 循环遍历, 如果找到就返回, 所以后面添加的会覆盖前面添加的.
- public string this[string key]
- {
- get
- { //_providers 也就是 IConfigurationRoot 里面的 IList<IConfigurationProvider>
- foreach (var provider in _providers.Reverse())
- {
- string value;
- if (provider.TryGet(key, out value))
- {
- return value;
- }
- }
- return null;
- }
- set
- {
- if (!_providers.Any())
- {
- throw new InvalidOperationException(Resources.Error_NoSources);
- }
- foreach (var provider in _providers)
- {
- provider.Set(key, value);
- }
- }
- }
对于 JSON,xml,INI 文件, 比如
- {
- "user": {
- "address": {
- "Provice": "浙江省",
- "city": "杭州市"
- },
- "name": "张三"
- }
- }
在 Data 中存储的 key 为 user:address:Province,user:address:city 和 user:name. 中间以 ":" 分割, 这个 ":" 是固定只读的, 不可以改变的.
三, 简单使用
创建一个 WebApi 项目, 修改 Program 代码如下:
- public static void Main(string[] args)
- {
- var configRoot = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())// 设置基础路径
- .AddJsonFile("a.json")// 加载配置
- .AddXmlFile("b.xml")
- .Build();
- var builder = new WebHostBuilder()
- .UseConfiguration(configRoot)
- .UseContentRoot(Directory.GetCurrentDirectory())
- .UseKestrel()
- .UseStartup<Startup>()
- .Build();
- builder.Run();
- }
然后当用的时候, 只需要注入 IConfiguration , 就能获取所有的配置.
来源: https://www.cnblogs.com/MicroHeart/p/10928888.html