.net core系列之《从源码对Configuration的底层运行机制进行分析》
通过对Configuration源代码的分析从而来自定义一个配置数据源
1、用反编译工具来看看AddJsonFile()这个方法究竟干了什么,源代码如下:
- public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path)
- {
- return builder.AddJsonFile(null, path, false, false);
- }
- public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional)
- {
- return builder.AddJsonFile(null, path, optional, false);
- }
- public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
- {
- return builder.AddJsonFile(null, path, optional, reloadOnChange);
- }
首先我们可以看到这3个重载方法,它们都是调用了下面这个方法:
- public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
- {
- if (builder == null)
- {
- throw new ArgumentNullException("builder");
- }
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentException(Microsoft.Extensions.Configuration.Json.Resources.Error_InvalidFilePath, "path");
- }
- return builder.AddJsonFile(delegate (JsonConfigurationSource s) {
- s.FileProvider = provider;
- s.Path = path;
- s.Optional = optional;
- s.ReloadOnChange = reloadOnChange;
- s.ResolveFileProvider();
- });
- }
而这个方法呢,又是调用了下面这个方法:
- public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action<JsonConfigurationSource> configureSource)
- {
- return builder.Add<JsonConfigurationSource>(configureSource);
- }
从上面的方法可以看出,类型参数为 JsonConfigurationSource 然后返回IConfigurationBuilder的扩展方法 Add<TSource>(this IConfigurationBuilder builder, Action<TSource> configureSource)
代码如下:
- public static IConfigurationBuilder Add<TSource>(this IConfigurationBuilder builder, Action<TSource> configureSource) where TSource: IConfigurationSource, new()
- {
- TSource source = Activator.CreateInstance<TSource>();
- if (configureSource != null)
- {
- configureSource(source);
- }
- return builder.Add(source);
- }
能过这个方法,创建 JsonConfigurationSource 的一个实例,最后返回 IConfigurationBuilder 中的 Add(IConfigurationSource source) 方法,接下来我们来看看在这个方法里都干了什么吧
- public IConfigurationBuilder Add(IConfigurationSource source)
- {
- if (source == null)
- {
- throw new ArgumentNullException("source");
- }
- this.Sources.Add(source);
- return this;
- }
- public IList<IConfigurationSource> Sources
- {
- [CompilerGenerated]
- get
- {
- return this.<Sources>k__BackingField;
- }
- }
通过以上代码我知道了,AddJsonFile()这个方法,创建了一个 JsonConfigurationSource 的一个实例,并将AddJsonFile()中的参数给了这个对象,然后将这个对象存到一个集合中。
2、接下来我们来看看Build()这个方法干了什么:
- public IConfigurationRoot Build()
- {
- List<IConfigurationProvider> list = new List<IConfigurationProvider>();
- using (IEnumerator<IConfigurationSource> enumerator = this.Sources.GetEnumerator())
- {
- while (enumerator.MoveNext())
- {
- IConfigurationProvider provider = enumerator.Current.Build(this);
- list.Add(provider);
- }
- }
- return new ConfigurationRoot((IList<IConfigurationProvider>) list);
- }
这个方法通过遍历你通过AddJsonFile()方法存放进去的 IConfigurationSource 的集合,然后通过调用 IConfigurationSource 的实现类的 Build方法 ,我们来看看这个方法是怎样的:
- public override IConfigurationProvider Build(IConfigurationBuilder builder)
- {
- base.EnsureDefaults(builder);
- return new JsonConfigurationProvider(this);
- }
这个方法返回一个 IConfigurationProvider 对象,被赋给了 List<IConfigurationProvider> 集合,接下来我们来看看 JsonConfigurationProvider 这个类里面有什么
- public override void Load(Stream stream)
- {
- try
- {
- base.Data = JsonConfigurationFileParser.Parse(stream);
- }
- catch (JsonReaderException exception)
- {
- string str = string.Empty;
- if (stream.get_CanSeek())
- {
- stream.Seek((long) 0L, (SeekOrigin) SeekOrigin.Begin);
- using (StreamReader reader = new StreamReader(stream))
- {
- IEnumerable<string> fileContent = ReadLines(reader);
- str = RetrieveErrorContext(exception, fileContent);
- }
- }
- throw new FormatException(Microsoft.Extensions.Configuration.Json.Resources.FormatError_JSONParseError((int) exception.LineNumber, str), exception);
- }
- }
我们看到了这里面有一个Load()方法,这个方法就是用来加载文件中的数据的。
然后我们接着分析上面还没分析的 return new ConfigurationRoot((IList<IConfigurationProvider>) list); 这段代码
这段代码返回了一个 ConfigurationRoot 对象,还将我们所有的 IConfigurationProvider 给传了进行,它想干嘛呢?
没错,上面虽然有Load()方法,但是没人调用啊。 ConfigurationRoot 这个类就是干这个的。
- public ConfigurationRoot(IList<IConfigurationProvider> providers)
- {
- if (providers == null)
- {
- throw new ArgumentNullException("providers");
- }
- this._providers = providers;
- foreach (IConfigurationProvider p in providers)
- {
- p.Load();
- ChangeToken.OnChange(delegate {
- return p.GetReloadToken();
- }, delegate {
- this.RaiseChanged();
- });
- }
- }
通过以上代码的分析我们知道了Configuration的底层运行机制
3、那么接下来我们来自定义一个获取自定义的文件的Configuration,能过以上代码我们可以分析出有几个重要的对象
1、JsonConfigurationSource:最后从这个对象的基类的Data属性中取值
2、JsonConfigurationProvider:这个里面的Load()方法用来加载文件数据
3、JsonConfigurationExtensions:这个是用来定义AddJsonFile()方法的
我们规定我们的文件后缀为.custom
CustomConfigurationSource类代码
- public class CustomConfigurationSource : FileConfigurationSource
- {
- private string path = string.Empty;
- public CustomConfigurationSource(string path)
- {
- this.path = path;
- }
- public override IConfigurationProvider Build(IConfigurationBuilder builder)
- {
- return new CustomConfigurationProvider(this.path);
- }
- }
CustomConfigurationProvider类代码
- public class CustomConfigurationProvider : ConfigurationProvider
- {
- private string path = string.Empty;
- public CustomConfigurationProvider(string path)
- {
- this.path = path;
- }
- public override void Load()
- {
- var lines = System.IO.File.ReadAllLines(this.path);
- var dict = new Dictionary<string, string>();
- foreach (var item in lines)
- {
- var items = item.Split("=");
- dict.Add(items[], items[]);
- }
- base.Data = dict;
- }
- }
CustomConfigurationExtensions类代码 :
- public static class CustomConfigurationExtensions
- {
- public static IConfigurationBuilder AddCustomFile(this IConfigurationBuilder builder, string path)
- {
- return builder.Add(new CustomConfigurationSource(path));
- }
- }
最终调用代码:
- static void Main(string[] args)
- {
- IConfiguration configuration = new ConfigurationBuilder()
- .SetBasePath(Environment.CurrentDirectory)
- .AddCustomFile("1.custom")
- .Build();;
- var info = configuration["host"];
- Console.WriteLine(info);
- Console.ReadKey();
- }
结果如下:
.net core系列之《从源码对Configuration的底层运行机制进行分析》的更多相关文章
- .net core系列之《.net core内置IOC容器ServiceCollection》
一.IOC介绍 IOC:全名(Inversion of Control)-控制反转 IOC意味着我们将对象的创建控制权交给了外部容器,我们不管它是如何创建的,我们只需要知道,当我们想要某个实例时,我们 ...
- Asp.Net Core 内置IOC容器的理解
Asp.Net Core 内置IOC容器的理解 01.使用IOC容器的好处 对接口和实现类由原来的零散式管理,到现在的集中式管理. 对类和接口之间的关系,有多种注入模式(构造函数注入.属性注入等). ...
- net core体系-web应用程序-4net core2.0大白话带你入门-8asp.net core 内置DI容器(DependencyInjection,控制翻转)的一点小理解
asp.net core 内置DI容器的一点小理解 DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IO ...
- NET Core 3.0 AutoFac替换内置DI的新姿势
原文:NET Core 3.0 AutoFac替换内置DI的新姿势 .NET Core 3.0 和 以往版本不同,替换AutoFac服务的方式有了一定的变化,在尝试着升级项目的时候出现了一些问题. 原 ...
- 浏览器扩展系列————给MSTHML添加内置脚本对象【包括自定义事件】
原文:浏览器扩展系列----给MSTHML添加内置脚本对象[包括自定义事件] 使用场合: 在程序中使用WebBrowser或相关的控件如:axWebBrowser等.打开本地的html文件时,可以在h ...
- 简单讲解Asp.Net Core自带IOC容器ServiceCollection
一. 理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二. 接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...
- ASP.NET Core 2.1 : 十二.内置日志、使用Nlog将日志输出到文件
应用离不开日志,虽然现在使用VS有强大的调试功能,开发过程中不复杂的情况懒得输出日志了(想起print和echo的有木有),但在一些复杂的过程中以及应用日常运行中的日志还是非常有用. ASP.NET ...
- asp.net core 内置DI容器的一点小理解
DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IOC). 具体体现为Micorosoft.Extensio ...
- 学习笔记:GLSL Core Tutorial – Vertex Shader(内置变量说明)
1.每个Vertex Shader都有用户定义的输入属性,例如:位置,法线向量和纹理坐标等.Vertex Shaders也接收一致变量(uniform variables). uniform vari ...
- .net core 2.0学习记录(三):内置IOC与DI的使用
本篇的话介绍下IOC和ID的含义以及如何使用.Net Core中的DI. 一.我是这么理解IOC和DI的: IOC:没有用IOC之前是直接new实例来赋值,使用IOC之后是通过在运行的时候根据配置来实 ...
随机推荐
- 关于.NET中FileSystemWatcher的一些不被人注意的细节
.NET 中的FileSystemWatcher可以监控文件系统中的更改.新建.删除和重命名,关于它的事件及属性的讨论有许多,但细节性的具体在什么情况下触发这些事件讨论不多.根据个人测试,总结如下: ...
- shell脚本杀进程重启
#!/bin/bash ID=`ps -ef | grep "abc" | grep -v "$0" | grep -v "grep" | ...
- 033-JsonUtils 工具类模板
模板一:使用的是jackson package cn.e3mall.common.utils; import java.util.List; import com.fasterxml.jackson. ...
- PHP之string之str_repeat()函数使用
str_repeat (PHP 4, PHP 5, PHP 7) str_repeat - Repeat a string str_repeat - 重复一个字符串 Description strin ...
- InnoDB存储引擎的表空间文件,重做日志文件
存储引擎文件:因为MySQL表存储引擎的关系,每个存储引擎都会有自己的文件来保存各种数据.这些存储引擎真正存储了数据和索引等数据. 表空间文件 InnoDB存储引擎在存储设计上模仿了Oracle,将存 ...
- 【LeetCode题解】94_二叉树的中序遍历
目录 [LeetCode题解]94_二叉树的中序遍历 描述 方法一:递归 Java 代码 Python代码 方法二:非递归 Java 代码 Python 代码 [LeetCode题解]94_二叉树的中 ...
- IOS折线图二
上周把项目的折线图给做了下,今天想着把它完善完善,自己设置了不同的数据源来测试,哈哈,还真遇到问题了, 就是给图表设置折点数为0时,视图显示的还是原来的,由于数据为空,应该将其设置为空,所以想着怎么把 ...
- 编译android源码遇到错误及其解决方法
升级ubuntu的14.04后,android的源码又编译错误了,一下是错误说明赫解决方法: 1.make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_ ...
- Toolstrip 工具栏控件
工具栏是另一种获取应用程序主要功能的常用方法,比起菜单更直观. Tool strip 控件是由system.Windows.forms.Toolstrip类提供的,作用是创建易于自定义的常用工具栏 ...
- redis中的发布订阅(Pub/Sub)
这里使用nodejs的redis模块说明,具体可见https://www.npmjs.com/package/redis,先来通过一个简单的例子了解下redis中的Pub/Sub具体怎么实现吧.. v ...