.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 ,就能获取所有的配置。
.Net Core中的配置文件源码解析的更多相关文章
- Scala 深入浅出实战经典 第65讲:Scala中隐式转换内幕揭秘、最佳实践及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- .Net Core缓存组件(Redis)源码解析
上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...
- 解析jQuery中extend方法--源码解析以及递归的过程《二》
源码解析 在解析代码之前,首先要了解extend函数要解决什么问题,以及传入不同的参数,会达到怎样的效果.extend函数内部处理传入的不同参数,返回处理后的对象. extend函数用来扩展对象,增加 ...
- .Net Core缓存组件(MemoryCache)源码解析
一.介绍 由于CPU从内存中读取数据的速度比从磁盘读取快几个数量级,并且存在内存中,减小了数据库访问的压力,所以缓存几乎每个项目都会用到.一般常用的有MemoryCache.Redis.MemoryC ...
- Spring中AOP相关源码解析
前言 在Spring中AOP是我们使用的非常频繁的一个特性.通过AOP我们可以补足一些面向对象编程中不足或难以实现的部分. AOP 前置理论 首先在学习源码之前我们需要了解关于AOP的相关概念如切点切 ...
- Spark Core 1.3.1源码解析及个人总结
本篇源码基于赵星对Spark 1.3.1解析进行整理.话说,我不认为我这下文源码的排版很好,不能适应的还是看总结吧. 虽然1.3.1有点老了,但对于standalone模式下的Master.Worke ...
随机推荐
- 【Maven】 (请使用 -source 8 或更高版本以启用 lambda 表达式)
在使用mvn install编译maven项目时,报了 “ (请使用 -source 8 或更高版本以启用 lambda 表达式)”错误,是因为设置的maven默认jdk编译版本太低的问题. 可使用两 ...
- Thinkphp5 获取执行的sql语句
获取最后执行的sql语句 $str_order_action = db('order_action')->getLastSql(); //获取最后执行的sql语句 获取执行的sql语句 $ord ...
- manjaro linux没有ll等命令的解决办法
编辑~/.bashrc, 添加alias 如下 vim ~/.bashrc设置别名. 添加如下行 alias ll='ls -alF' alias la='ls -A' alias vi='vim' ...
- Python之简单Socket编程
Socket编程这块儿还是比较重要的,记录一下:实现服务器端和客户端通信(客户端发送系统指令,如ipconfig等,服务器端执行该指令,然后将指令返回结果给客户端再传过去,设置一次最多直接收1024字 ...
- R-data.table
data.table可以扩展和增强data.frame的功能,在分组操作和组合时访问速度更快. require(data.table) theDT = data.table(A=1:10, B=let ...
- Linux之crond 服务介绍
在介绍crond之前,先科普一下什么是进程?什么是线程?什么是程序? 程序:程序是一组指令及参数的集合,指令按照既定的逻辑控制计算机运行.进程则是运行着的程序,是操作系统执行的基本单位.线程则是为了节 ...
- 异常 ndroid.view.InflateException: Binary XML file line #8: Error inflating class com.ouyang.test.MyView
发现自定义view时出现ndroid.view.InflateException: Binary XML file line #8: Error inflating class com.ouyang. ...
- vi 编辑器命令
插入命令 a append after the cursor A append after the current line i insert before the cursor I insert b ...
- dotnet core 运行程序注意事项
.net core 程序 debug版本无法直接运行,因为没有相关的dll,只有在进入项目文件夹那一层,执行 dotnet run 来运行,会自动链接 当前用户的个人文件夹下的 .nuget/.pac ...
- luogu2766 最长不下降子序列问题
第一问DP水过.dp[i]代表以i结尾的最长不下降子序列长度. 二三问网络流. 第二问是说每个子序列不能重复使用某个数字. 把每个点拆成p(i),q(i).连边. 要是dp[i]=1,连源,p(i) ...