关于Asp.net core配置信息读取的源码分析梳理

8d28cd4f5258f07f5b97f62f724995c3.gif

概述

我们都知道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) 。关系如下图:

c926aba49f759f10fc97d045eb6e936b.png

e0d3b91dfecbaaa46e616bc6e3fecc20.png

 看完上面这个关系图后,我们紧接着上面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())));}}
}
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源码真的特别优秀,很值得花一番时间去看看!从其中可以学到许多架构知识!

— —往日推荐— —

  1. github上star23k的程序员必备通用简历模板

  2. Windows+.NetCore+git+IIS在Jenkins上的自动化部署入门

  3. C# 创建单例你会几种方式?

  4. 一个小时开发的直播推拉流软件来了

  5. 关于数据库建表是否建立外键的争论,你有什么样的观点?

  6. 常见的23种设计模式彩图过来了解一下

  7. 什么是线程同步?又如何解决线程同步问题?

  8. 使用.net 和Selenium模拟百度登录

  9. 四种软件架构,看看你属于哪个层次?

  10. .net爬虫是一门必修课

  11. .net下使用Selenium、PhantomJS

  12. 在.net平台使用Quartz+Topshelf创建windows服务

  13. 极简实用的Asp.NetCore模块化框架决定免费开源了

  14. 关于Asp.Net Core如何更完美地配置swagger

  15. ASP.NET Core如何自动生成小写的破折号路由

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293921.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MCGS与PLC通讯不上

为什么80%的码农都做不了架构师&#xff1f;>>> 组态串口参数错误 应为偶校验 转载于:https://my.oschina.net/5star/blog/118301

MySQL案例分析--QueryCache

QueryCache联动内容:http://blog.itpub.net/29510932/viewspace-1694922/ -------------------------------------------------------------------------------------------------正文--------------------------------------------------------------------------------------…

Android之PowerManager简介

android.os. PowerManager 通过 PowerManager 类我们可以对设备的电源进行管理。对该类API的使用将影响到电池寿命。只有在必须使用WakeLocks的时候,才使用WakeLocks,且在不使用它的时候要及时释放(release). 默认情况下,当用户对手机有一段时间没有操作后࿰

什么时候告白最合适?

1 电饭煲吐血了&#xff01;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 比冰淇淋掉地上更悲剧的事&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 老师的火气又上去了▼4 什么时候最适合告白&#xff08;via.银教授&#xff0c;侵删&#xff09;▼…

helloworld:一个完整的WCF案例

服务端 1.创建一个空的解决方案:WCFDemo: 2.创建一个宿主控制台程序&#xff1a;Host 3.右击Host项目&#xff0c;选择“添加”--“新建项”&#xff0c;选择“WCF服务”创建名为“Service1.cs”的服务 如此&#xff1a;VS2010已经为我们创建了 IService1.cs Service1.cs a…

极简实用的Asp.NetCore模块化框架决定免费开源了

背景在开发这个框架之前&#xff0c;前前后后看过好几款模块化的框架&#xff0c;最后在一段时间内对ABP VNext痛下狠心&#xff0c;研究一段时间后&#xff0c;不得不说 ABP VNext的代码层面很规范&#xff0c;也都是一些最佳实践&#xff0c;开发出一个模块效率也很高。但不得…

我做的OSC界面

2019独角兽企业重金招聘Python工程师标准>>> 转载于:https://my.oschina.net/hotbain/blog/118542

Fragment生命周期

通过Android Studio创建包含两个Fragment的Activity&#xff1a;QuestListFragment、QuestInputFragment 调用的过程如下&#xff1a; 打开APPQuestListFragment﹕ onAttachQuestListFragment﹕ onCreateQuestListFragment﹕ onCreateViewQuestListFragment﹕ onViewCreatedQue…

使用Nagios监控esx、esxi、vcenter

系统环境&#xff1a;Centos6.3 最小化安装环境准备yum install –y libxml2-devel make gcc1、安装前准备 &#xff08;1&#xff09;创建nagios用户和用户组 [rootlocalhost ~]#useradd -s /sbin/nologin nagios [rootlocalhost ~]#mkdir /usr/local/nagios [rootlocalhost ~…

龙芯上市是自主路线被广泛认可的风向标

日前&#xff0c;龙芯通过科创板上市委员会审核&#xff0c;此次计划募资35.12亿元。其中&#xff0c;12.58亿元用于先进制程芯片研发及产业化项目&#xff0c;10.54亿元用于高性能通用图形处理器芯片及系统研发项目&#xff1b;12亿元用于补充流动资金。公开材料还披露了很多细…

量子计算机是程序员的未来,研究者:量子计算机一旦成功问世,时间也许会失去存在的意义...

贝尔实验室的科学家索尔&#xff0c;自从在1994年35界计算科学基础年会上提出量子算法后&#xff0c;立刻引起全世界科学界的轰动&#xff0c;量子计算机的研究热潮自此到来。量子计算机的运行方式以及存储计算方式&#xff0c;都与经典计算机存在着很大不同。经典计算机的存储…

.NET 现代化动态 LINQ 库 Gridify

动态 LINQ大家好&#xff0c;我是等天黑, 这次继续介绍开源项目&#xff0c;Gridify 是一个现代化动态 LINQ 库&#xff0c;它以最简单的方式将您的字符串转换为 LINQ 查询&#xff0c;并且有出色的性能。它还提供了一种使用基于文本的数据应用过滤、排序和分页的简单方法&…

brew mysql 添加修改mysql配置

为什么80%的码农都做不了架构师&#xff1f;>>> brew安装的MySQL是没有默认配置文件的&#xff0c;因此Mysql使用默认配置启动。我们需要手动创建my.cnf去覆盖默认配置。在/usr/local/opt/mysql 下确实有 my.cnf 但是并没有在启用中&#xff0c;应该是作为一个示例…

LINUX BASH SHELL,小小学习一下

注意点要注意的&#xff1a; 整数运算一般通过 let 和 expr 这两个指令来实现&#xff0c;如对变量 x 加 1 可以写作&#xff1a;let "x $x 1" 或者 xexpr $x 1 两个比较表格要记得&#xff1a; 对应的操作 整数操作 字符串操作 相同 -eq 不同 -ne ! 大…

“人肉”背后隐藏的网络风险

“遭此不幸”的演艺界大碗包括 Jay-Z、碧昂斯 (Beyonce)、布兰妮。斯皮尔斯 (Britney Spears) 以及金。卡戴珊 (Kim Kardashian) 等&#xff0c;他们的个人信息被公诸于众。此外&#xff0c;这次泄露事件的受害者甚至包括美国第一夫人米歇尔。奥巴马 (Michelle Obama)、副总统乔…

数学系都是怎么发「新年祝福」的?

全世界只有3.14 % 的人关注了爆炸吧知识过年啦&#xff01;你都收到什么样的祝福&#xff1f;&#xff08;快到留言区留言&#xff09;不过看来看去&#xff0c;还是超模君曾经收到的一条祝福最特别了&#xff01;超模君今天把这份新年祝福分享给大家&#xff1a;长按图片可保存…

NET 6 中新增的LINQ 方法

.NET 6 中添加了许多 LINQ 方法。下表中列出的大多数新方法在 System.Linq.Queryable 类型中具有等效方法。欢迎关注如果你刻意练习某件事情请超过10000小时&#xff0c;那么你就会达到世界级别今晚打老虎TryGetNonEnumeratedCount 尝试在不强制枚举的情况下确定序列中的元素数…