关于Asp.net core配置信息读取的源码分析梳理
概述
我们都知道asp.net core配置信息的读取离不开IConfigurationSource和IConfigurationProvider这两个类,ConfigurationSource可以提供一个ConfigurationProvider,然后去读取信息。究竟他们之间有着怎样的千丝万缕,我们一起来看看源码。
首先我们来建立一个.net core控制台项目,来运行以下代码:
class Program
{
static void Main(string[] args)
{
ConfigurationBuilder configBuilder = new ConfigurationBuilder();
configBuilder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configFile = configBuilder.Build(); Console.ReadKey();
}
}
短短几行 代码看起来很简单,就是用来读取appsettings.json文件中的配置信息。然而我们今天想搞清楚其背后运行的原理,要花点时间。
首先、我们根据代码ConfigurationBuilder configBuilder = new ConfigurationBuilder();知道创建了一个configBuilder对象;
其次,configBuilder.SetBasePath(Directory.GetCurrentDirectory()) 该代码的调用我们也能大概见名知义,获取当前的目录;
接下来,重点来了,configBuilder.AddJsonFile("appsettings.json")的实现究竟是怎样的?我们来看下源码的实现:
f12进去后源码如下:
/// <summary>Extension methods for adding <see cref="T:Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider" />.</summary>
public static class JsonConfigurationExtensions
{
/// <summary>Adds the JSON configuration provider at <paramref name="path" /> to <paramref name="builder" />.</summary>
/// <param name="builder">The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" /> to add to.</param>
/// <param name="path">Path relative to the base path stored in
/// <see cref="P:Microsoft.Extensions.Configuration.IConfigurationBuilder.Properties" /> of <paramref name="builder" />.</param>
/// <returns>The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" />.</returns>
public static IConfigurationBuilder AddJsonFile(
this IConfigurationBuilder builder,
string path)
{
return builder.AddJsonFile((IFileProvider) null, path, false, false);
}
}
紧接着f12再看实现的源码,依然在JsonConfigurationExtensions这个扩展类里面:
public static IConfigurationBuilder AddJsonFile(
this IConfigurationBuilder builder,
IFileProvider provider,
string path,
bool optional,
bool reloadOnChange)
{
if (builder == null)
throw new ArgumentNullException(nameof (builder));
if (string.IsNullOrEmpty(path))
throw new ArgumentException(SR.Error_InvalidFilePath, nameof (path));
return builder.AddJsonFile((Action<JsonConfigurationSource>) (s =>
{
s.FileProvider = provider;
s.Path = path;
s.Optional = optional;
s.ReloadOnChange = reloadOnChange;
s.ResolveFileProvider();
}));
}
这时候有没有发现builder.AddJsonFile((Action<JsonConfigurationSource>)这个方法里面出现了一个关键的信息点:JsonConfigurationSource (JsonConfigurationSource 继承抽象类FileConfigurationSource,而FileConfigurationSource:IConfigurationSource) 。 关系如下图:


看完上面这个关系图后,我们紧接着上面builder.AddJsonFile()的实现源码继续f12往下,源码如下:
//该代码依然在JsonConfigurationExtensions类里面
public static IConfigurationBuilder AddJsonFile(
this IConfigurationBuilder builder,
Action<JsonConfigurationSource> configureSource)
{
return ConfigurationExtensions.Add<JsonConfigurationSource>(builder, (Action<M0>) configureSource);
}
我们看到上面的扩展方法实现是ConfigurationExtensions.Add...,再往下看实现:
public static class ConfigurationExtensions
{
/// <summary>Adds a new configuration source.</summary>
/// <param name="builder">The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" /> to add to.</param>
/// <param name="configureSource">Configures the source secrets.</param>
/// <typeparam name="TSource" />
/// <returns>The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" />.</returns>
public static IConfigurationBuilder Add<TSource>(
this IConfigurationBuilder builder,
Action<TSource> configureSource)
where TSource : IConfigurationSource, new()
{
TSource source = new TSource();
if (configureSource != null)
configureSource(source);
return builder.Add((IConfigurationSource) source);
}
}
到这里我们看到了其实就是IConfigurationBuilder调用了Add方法,添加了一个数据源(JsonConfigurationSource),至于JsonConfigurationSource类里面做了什么,我们看下实现。
public class JsonConfigurationSource : FileConfigurationSource
{
/// <summary>Builds the <see cref="T:Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider" /> for this source.</summary>
/// <param name="builder">The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationBuilder" />.</param>
/// <returns>A <see cref="T:Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider" /></returns>
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
this.EnsureDefaults(builder);
return (IConfigurationProvider) new JsonConfigurationProvider(this);
}
}
JsonConfigurationSource类面的Build方法提供了一个JsonConfigurationProvider类,这里再贴下JsonConfigurationProvider类里面的代码:
/// <summary>A JSON file based <see cref="T:Microsoft.Extensions.Configuration.FileConfigurationProvider" />.</summary>
public class JsonConfigurationProvider : FileConfigurationProvider
{
/// <summary>Initializes a new instance with the specified source.</summary>
/// <param name="source">The source settings.</param>
public JsonConfigurationProvider(JsonConfigurationSource source)
: base((FileConfigurationSource) source)
{
} /// <summary>Loads the JSON data from a stream.</summary>
/// <param name="stream">The stream to read.</param>
public virtual void Load(Stream stream)
{
try
{
this.set_Data(JsonConfigurationFileParser.Parse(stream));
}
catch (JsonException ex)
{
throw new FormatException(SR.Error_JSONParseError, (Exception) ex);
}
}
}
关于JsonConfigurationProvider里面的Load就是去读取信息的实现,至于Load的具体实现我们不再深究。我们回到最初的控制台configBuilder.Build(),看看其的实现:
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);
}
}
看到这个源码的时候有没有种豁然开朗的感觉,前面我们说到IConfigurationBuilder调用了Add方法添加一个数据源,并没说添加了一个数据源存在了哪里,到底有什么用处,现在在上面ConfigurationBuilder类里面看到存在了Sources 集合里面。然后configBuilder.Build()
去调用的时候遍历数据源(Sources )集合,紧接着source (IConfigurationSource)调用了Build方法构建了一个configurationProvider对象存到configurationProviderList集合里面,最后在返回一个ConfigurationRoot对象的构造函数里面传递了configurationProviderList集合去执行。
贴上ConfigurationRoot的源码:
public class ConfigurationRoot : IConfigurationRoot, IConfiguration, IDisposable
{ private readonly IList<IConfigurationProvider> _providers;
private readonly IList<IDisposable> _changeTokenRegistrations; /// <summary>Initializes a Configuration root with a list of providers.</summary>
/// <param name="providers">The <see cref="T:Microsoft.Extensions.Configuration.IConfigurationProvider" />s for this configuration.</param>
public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
if (providers == null)
throw new ArgumentNullException(nameof (providers));
this._providers = providers;
this._changeTokenRegistrations = (IList<IDisposable>) new List<IDisposable>(providers.Count);
foreach (IConfigurationProvider provider in (IEnumerable<IConfigurationProvider>) providers)
{
IConfigurationProvider p = provider;
p.Load();
this._changeTokenRegistrations.Add(ChangeToken.OnChange((Func<IChangeToken>) (() => p.GetReloadToken()), (Action) (() => this.RaiseChanged())));
}
}
}
看到没,最后providers去调用了load方法。
结语
就上面的控制台代码来说IConfigurationSource对应的实现是JsonConfigurationSource;IConfigurationProvider,抽象类ConfigurationProvider对应的实现为JsonConfigurationProvider。如果我们要换成别的文件格式呢?比如ini,怎样自定义配置源呢?大家可以先想想,其实也很简单,下次跟大家分享。
最后说真的,.netCore源码真的特别优秀,很值得花一番时间去看看!从其中可以学到许多架构知识!
关于Asp.net core配置信息读取的源码分析梳理的更多相关文章
- Spring Cloud Nacos实现动态配置加载的源码分析
理解了上述Environment的基本原理后,如何从远程服务器上加载配置到Spring的Environment中. NacosPropertySourceLocator 顺着前面的分析思路,我们很自然 ...
- Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]
目录 前言 现象 源码分析 实战例子 总结 参考资料 前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作 ...
- zookeeper配置中心实战--solrcloud zookeeper配置中心原理及源码分析
程序的发展,需要引入集中配置: 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址…… 并且对配置的期望也越来越高,配置修改后实时生效,灰度发布,分环境.分集群管理配 ...
- ASP.NET CORE配置信息
做个笔记,原文链接 除了应用 IOptions<T> .Value的方式对配置信息进行全局注册外可以应用的另一个微软给出的组件,需要依赖两个包 Microsoft.Extensions.C ...
- ASP.NET CORE小试牛刀:干货(完整源码)
扯淡 .NET Core 的推出让开发者欣喜万分,从封闭到拥抱开源十分振奋人心.对跨平台的支持,也让咱.NET开发者体验了一把 Write once,run any where 的感觉!近期离职后,时 ...
- ASP.NET CORE 入门教程(附源码)
ASP.NET CORE 入门教程 第一课 基本概念 基本概念 Asp.Net Core Mvc是.NET Core平台下的一种Web应用开发框架 符合Web应用特点 .NET Core跨平台解决方案 ...
- Asp.net core 项目实战 新闻网站+后台 源码、设计原理 、视频教程
首先说明,视频教程.源码并非本人原创 本人将项目分割开,并写了一些说明. 该视频教程 地址 https://study.163.com/course/courseMain.htm?courseId= ...
- org.springframework.core.io包内的源码分析
前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...
- [Asp.net 5] Caching-缓存架构与源码分析
首先奉献caching的开源地址[微软源码] 1.工程架构 为了提高程序效率,我们经常将一些不频繁修改,但是使用了还很大的数据进行缓存.尤其是互联网产品,缓存可以说是提升效率优化第一利器.微软为我们实 ...
随机推荐
- Shell系列(4)- 历史命令
格式:history [选项] [历史命令保存文件] 选项: -c:清空历史命令 -w:把缓存中的历史命令写入到历史命令保存文件~ /.bash_history;用户的家目录下 例子: [root@l ...
- Elasticsearch2.4.6版本 在linux 命令行 对数据的增删改操作
一._cluster系列:查询设置集群状态 1.设置集群状态 curl -XGET 10.68.120.167:9204/_cluster/health?pretty=true pretty=true ...
- P3235-[HNOI2014]江南乐【整除分块,SG函数】
正题 题目链接:https://www.luogu.com.cn/problem/P3235 题目大意 \(T\)组游戏,固定给出\(F\).每组游戏有\(n\)个石头,每次操作的人可以选择一个数量不 ...
- P5369-[PKUSC2018]最大前缀和【状压dp】
正题 题目链接:https://www.luogu.com.cn/problem/P5369 题目大意 一个数列\(a\)的权值定义为\(max\{\sum_{i=1}^ka_i\}(k\in[1,n ...
- 被校园网限速限流的日子 | 路由代理ipv6访问的操作手册
一 前 言 你是否还在为校园网的收费而小心翼翼?你是否还在为网速不够快而影响科研进程? 你是否还在为处理舍友关系而费经心思? 你是否还在为不能给舍友提供价值而苦恼? 那么,叶子团队或许能够帮助到你解决 ...
- Python异常代码含义对照表
Python常见的异常提示及含义对照表如下: 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是 ...
- Elasticsearch 存储成本省 60%,稿定科技干货分享
背景 稿定科技旗下稿定设计产品是一个聚焦商业设计的多场景在线设计平台,打破了软硬件间的技术限制,汇集创意内容与设计工具于一体,为不同场景下的设计需求提供优质的解决方案,满足图片.视频等全类型媒介的设计 ...
- MySQL ENGINES 引擎
引擎 存储引擎是数据库底层软件组织. 数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据. 不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能. MySQL的核心就是存储引擎 ...
- FastAPI 学习之路(六)查询参数,字符串的校验
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(八)路径参数和数值的校验
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...