概述

我们都知道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配置信息读取的源码分析梳理的更多相关文章

  1. Spring Cloud Nacos实现动态配置加载的源码分析

    理解了上述Environment的基本原理后,如何从远程服务器上加载配置到Spring的Environment中. NacosPropertySourceLocator 顺着前面的分析思路,我们很自然 ...

  2. Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]

    目录 前言 现象 源码分析 实战例子 总结 参考资料 前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作 ...

  3. zookeeper配置中心实战--solrcloud zookeeper配置中心原理及源码分析

    程序的发展,需要引入集中配置: 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址…… 并且对配置的期望也越来越高,配置修改后实时生效,灰度发布,分环境.分集群管理配 ...

  4. ASP.NET CORE配置信息

    做个笔记,原文链接 除了应用 IOptions<T> .Value的方式对配置信息进行全局注册外可以应用的另一个微软给出的组件,需要依赖两个包 Microsoft.Extensions.C ...

  5. ASP.NET CORE小试牛刀:干货(完整源码)

    扯淡 .NET Core 的推出让开发者欣喜万分,从封闭到拥抱开源十分振奋人心.对跨平台的支持,也让咱.NET开发者体验了一把 Write once,run any where 的感觉!近期离职后,时 ...

  6. ASP.NET CORE 入门教程(附源码)

    ASP.NET CORE 入门教程 第一课 基本概念 基本概念 Asp.Net Core Mvc是.NET Core平台下的一种Web应用开发框架 符合Web应用特点 .NET Core跨平台解决方案 ...

  7. Asp.net core 项目实战 新闻网站+后台 源码、设计原理 、视频教程

    首先说明,视频教程.源码并非本人原创 本人将项目分割开,并写了一些说明. 该视频教程 地址  https://study.163.com/course/courseMain.htm?courseId= ...

  8. org.springframework.core.io包内的源码分析

    前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...

  9. [Asp.net 5] Caching-缓存架构与源码分析

    首先奉献caching的开源地址[微软源码] 1.工程架构 为了提高程序效率,我们经常将一些不频繁修改,但是使用了还很大的数据进行缓存.尤其是互联网产品,缓存可以说是提升效率优化第一利器.微软为我们实 ...

随机推荐

  1. Python - 生成requirement.text 文件

    前言 该篇操作笔记摘自小菠萝 Python项目中,一般都会有一个 requirements.txt 文件 这个文件主要是用于记录当前项目下的所有依赖包及其精确的版本号,以方便在一个新环境下更快的进行部 ...

  2. [转载]Windows 2008多用户同时远程登陆配置方法

    有些朋友需要在在使用Windows 2008远程登录功能时,进行多用户登录,那么就可以采用以下配置方法: 首先要启用远程桌面这一功能:右击"我的电脑"→ 属性 → 远程配置 → 远 ...

  3. 鸿蒙源码分析系列(总目录) | 百万汉字注解 百篇博客分析 | 深入挖透OpenHarmony源码 | v8.23

    百篇博客系列篇.本篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o 百篇博客.往期回顾 在给OpenHarmony内核源码加注过程中,整理出以下 ...

  4. PolarDB PostgreSQL 架构原理解读

    背景 PolarDB PostgreSQL(以下简称PolarDB)是一款阿里云自主研发的企业级数据库产品,采用计算存储分离架构,兼容PostgreSQL与Oracle.PolarDB 的存储与计算能 ...

  5. 解决 Asp.Net5 在视频文件下载预览时无法快进的问题

    前情提要 https://www.cnblogs.com/puzhiwei/p/15265005.html 在解决.Net5 如何修改Content-Disposition实现在线预览的功能后,我又遇 ...

  6. 踩坑系列《一》数据库建表权限 CREATE command denied to user for table

    今天在表中用Navicat连接服务器上的mysql账号进行建表,报了个这样类似的错, CREATE command denied to user for table 是数据库权限设置的问题,所以无法进 ...

  7. 常见的==和equals比较

    在笔试上碰到很多这样类似的题,全部整理到这里 String a = "Hello"; String b = "Hello"; String c = new St ...

  8. The art of multipropcessor programming 读书笔记-硬件基础1

    本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...

  9. 从零入门 Serverless | Serverless Kubernetes 应用部署及扩缩容

    作者 | 邓青琳(轻零) 阿里云技术专家 导读:本文分为三个部分,首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署,其次介绍 Serverless Kuberne ...

  10. java 从零开始手写 RPC (07)-timeout 超时处理

    <过时不候> 最漫长的莫过于等待 我们不可能永远等一个人 就像请求 永远等待响应 超时处理 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RP ...