• .Net Core中的配置文件源码解析


    一、配置简述

      之前在.Net Framework平台开发时,一般配置文件都是xml格式的Web.config,而需要配置其他格式的文件就需要自己去读取内容,加载配置了。.而Net Core支持从命令行、环境变量、文件、内存、Key-per-file中加载配置,其中文件包括xml、ini、json三种文件格式。这里需要说明一下,不论哪种格式的配置文件,加载到程序中最终会以Key/Value形式保存,源码中将所有配置读取出来并保存在  Dictionary<string, string> Data  的字典中。额外说明一下Key-per-file配置方式是以文件名称为key,文件内容为value的形式。

    二、源码解析

      点击查看源码,我画了一个主要类之间的逻辑关系图,如下:

    实线表示继承关系,每条虚线表示意义已经在上面表明。可以分为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 ,就能获取所有的配置。

  • 相关阅读:
    下载字体的正确姿势
    字体基础知识与实际运用
    CSP复习与模板
    地理必修三知识点
    LaTeX公式手册(全网最全)
    动态规划求解0/1背包问题
    JavaScript对象简介(一)
    DOM文档对象模型简介
    SQLServer 的case when语句使用实现统计
    批量初始化数组和memset函数
  • 原文地址:https://www.cnblogs.com/MicroHeart/p/10928888.html
Copyright © 2020-2023  润新知