通过对Configuration源代码的分析从而来自定义一个配置数据源

1、用反编译工具来看看AddJsonFile()这个方法究竟干了什么,源代码如下:

  1. public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path)
  2. {
  3. return builder.AddJsonFile(null, path, false, false);
  4. }
  5.  
  6. public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional)
  7. {
  8. return builder.AddJsonFile(null, path, optional, false);
  9. }
  10.  
  11. public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
  12. {
  13. return builder.AddJsonFile(null, path, optional, reloadOnChange);
  14. }

首先我们可以看到这3个重载方法,它们都是调用了下面这个方法:

  1. public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
  2. {
  3. if (builder == null)
  4. {
  5. throw new ArgumentNullException("builder");
  6. }
  7. if (string.IsNullOrEmpty(path))
  8. {
  9. throw new ArgumentException(Microsoft.Extensions.Configuration.Json.Resources.Error_InvalidFilePath, "path");
  10. }
  11. return builder.AddJsonFile(delegate (JsonConfigurationSource s) {
  12. s.FileProvider = provider;
  13. s.Path = path;
  14. s.Optional = optional;
  15. s.ReloadOnChange = reloadOnChange;
  16. s.ResolveFileProvider();
  17. });
  18. }

而这个方法呢,又是调用了下面这个方法:

  1. public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action<JsonConfigurationSource> configureSource)
  2. {
  3. return builder.Add<JsonConfigurationSource>(configureSource);
  4. }

从上面的方法可以看出,类型参数为 JsonConfigurationSource 然后返回IConfigurationBuilder的扩展方法 Add<TSource>(this IConfigurationBuilder builder, Action<TSource> configureSource)

代码如下:

  1. public static IConfigurationBuilder Add<TSource>(this IConfigurationBuilder builder, Action<TSource> configureSource) where TSource: IConfigurationSource, new()
  2. {
  3. TSource source = Activator.CreateInstance<TSource>();
  4. if (configureSource != null)
  5. {
  6. configureSource(source);
  7. }
  8. return builder.Add(source);
  9. }

能过这个方法,创建 JsonConfigurationSource 的一个实例,最后返回 IConfigurationBuilder  中的 Add(IConfigurationSource source) 方法,接下来我们来看看在这个方法里都干了什么吧

  1. public IConfigurationBuilder Add(IConfigurationSource source)
  2. {
  3. if (source == null)
  4. {
  5. throw new ArgumentNullException("source");
  6. }
  7. this.Sources.Add(source);
  8. return this;
  9. }
  10.  
  11. public IList<IConfigurationSource> Sources
  12. {
  13. [CompilerGenerated]
  14. get
  15. {
  16. return this.<Sources>k__BackingField;
  17. }
  18. }

通过以上代码我知道了,AddJsonFile()这个方法,创建了一个 JsonConfigurationSource 的一个实例,并将AddJsonFile()中的参数给了这个对象,然后将这个对象存到一个集合中。

2、接下来我们来看看Build()这个方法干了什么:

  1. public IConfigurationRoot Build()
  2. {
  3. List<IConfigurationProvider> list = new List<IConfigurationProvider>();
  4. using (IEnumerator<IConfigurationSource> enumerator = this.Sources.GetEnumerator())
  5. {
  6. while (enumerator.MoveNext())
  7. {
  8. IConfigurationProvider provider = enumerator.Current.Build(this);
  9. list.Add(provider);
  10. }
  11. }
  12. return new ConfigurationRoot((IList<IConfigurationProvider>) list);
  13. }

这个方法通过遍历你通过AddJsonFile()方法存放进去的 IConfigurationSource 的集合,然后通过调用 IConfigurationSource 的实现类的 Build方法 ,我们来看看这个方法是怎样的:

  1. public override IConfigurationProvider Build(IConfigurationBuilder builder)
  2. {
  3. base.EnsureDefaults(builder);
  4. return new JsonConfigurationProvider(this);
  5. }

这个方法返回一个 IConfigurationProvider  对象,被赋给了 List<IConfigurationProvider>  集合,接下来我们来看看 JsonConfigurationProvider 这个类里面有什么

  1. public override void Load(Stream stream)
  2. {
  3. try
  4. {
  5. base.Data = JsonConfigurationFileParser.Parse(stream);
  6. }
  7. catch (JsonReaderException exception)
  8. {
  9. string str = string.Empty;
  10. if (stream.get_CanSeek())
  11. {
  12. stream.Seek((long) 0L, (SeekOrigin) SeekOrigin.Begin);
  13. using (StreamReader reader = new StreamReader(stream))
  14. {
  15. IEnumerable<string> fileContent = ReadLines(reader);
  16. str = RetrieveErrorContext(exception, fileContent);
  17. }
  18. }
  19. throw new FormatException(Microsoft.Extensions.Configuration.Json.Resources.FormatError_JSONParseError((int) exception.LineNumber, str), exception);
  20. }
  21. }

我们看到了这里面有一个Load()方法,这个方法就是用来加载文件中的数据的。

然后我们接着分析上面还没分析的  return new ConfigurationRoot((IList<IConfigurationProvider>) list); 这段代码

这段代码返回了一个 ConfigurationRoot 对象,还将我们所有的 IConfigurationProvider 给传了进行,它想干嘛呢?

没错,上面虽然有Load()方法,但是没人调用啊。 ConfigurationRoot  这个类就是干这个的。

  1. public ConfigurationRoot(IList<IConfigurationProvider> providers)
  2. {
  3. if (providers == null)
  4. {
  5. throw new ArgumentNullException("providers");
  6. }
  7. this._providers = providers;
  8. foreach (IConfigurationProvider p in providers)
  9. {
  10. p.Load();
  11. ChangeToken.OnChange(delegate {
  12. return p.GetReloadToken();
  13. }, delegate {
  14. this.RaiseChanged();
  15. });
  16. }
  17. }

通过以上代码的分析我们知道了Configuration的底层运行机制

3、那么接下来我们来自定义一个获取自定义的文件的Configuration,能过以上代码我们可以分析出有几个重要的对象

  1、JsonConfigurationSource:最后从这个对象的基类的Data属性中取值

  2、JsonConfigurationProvider:这个里面的Load()方法用来加载文件数据

  3、JsonConfigurationExtensions:这个是用来定义AddJsonFile()方法的

我们规定我们的文件后缀为.custom

CustomConfigurationSource类代码

  1. public class CustomConfigurationSource : FileConfigurationSource
  2. {
  3. private string path = string.Empty;
  4. public CustomConfigurationSource(string path)
  5. {
  6. this.path = path;
  7. }
  8. public override IConfigurationProvider Build(IConfigurationBuilder builder)
  9. {
  10. return new CustomConfigurationProvider(this.path);
  11. }
  12. }

CustomConfigurationProvider类代码

  1. public class CustomConfigurationProvider : ConfigurationProvider
  2. {
  3. private string path = string.Empty;
  4. public CustomConfigurationProvider(string path)
  5. {
  6. this.path = path;
  7. }
  8. public override void Load()
  9. {
  10. var lines = System.IO.File.ReadAllLines(this.path);
  11. var dict = new Dictionary<string, string>();
  12. foreach (var item in lines)
  13. {
  14. var items = item.Split("=");
  15. dict.Add(items[], items[]);
  16. }
  17. base.Data = dict;
  18. }
  19. }

CustomConfigurationExtensions类代码 :

  1. public static class CustomConfigurationExtensions
  2. {
  3. public static IConfigurationBuilder AddCustomFile(this IConfigurationBuilder builder, string path)
  4. {
  5. return builder.Add(new CustomConfigurationSource(path));
  6. }
  7. }

最终调用代码:

  1. static void Main(string[] args)
  2. {
  3. IConfiguration configuration = new ConfigurationBuilder()
  4. .SetBasePath(Environment.CurrentDirectory)
  5. .AddCustomFile("1.custom")
  6. .Build();;
  7. var info = configuration["host"];
  8. Console.WriteLine(info);
  9. Console.ReadKey();
  10. }

结果如下:

.net core系列之《从源码对Configuration的底层运行机制进行分析》的更多相关文章

  1. .net core系列之《.net core内置IOC容器ServiceCollection》

    一.IOC介绍 IOC:全名(Inversion of Control)-控制反转 IOC意味着我们将对象的创建控制权交给了外部容器,我们不管它是如何创建的,我们只需要知道,当我们想要某个实例时,我们 ...

  2. Asp.Net Core 内置IOC容器的理解

    Asp.Net Core 内置IOC容器的理解 01.使用IOC容器的好处 对接口和实现类由原来的零散式管理,到现在的集中式管理. 对类和接口之间的关系,有多种注入模式(构造函数注入.属性注入等). ...

  3. net core体系-web应用程序-4net core2.0大白话带你入门-8asp.net core 内置DI容器(DependencyInjection,控制翻转)的一点小理解

    asp.net core 内置DI容器的一点小理解   DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IO ...

  4. NET Core 3.0 AutoFac替换内置DI的新姿势

    原文:NET Core 3.0 AutoFac替换内置DI的新姿势 .NET Core 3.0 和 以往版本不同,替换AutoFac服务的方式有了一定的变化,在尝试着升级项目的时候出现了一些问题. 原 ...

  5. 浏览器扩展系列————给MSTHML添加内置脚本对象【包括自定义事件】

    原文:浏览器扩展系列----给MSTHML添加内置脚本对象[包括自定义事件] 使用场合: 在程序中使用WebBrowser或相关的控件如:axWebBrowser等.打开本地的html文件时,可以在h ...

  6. 简单讲解Asp.Net Core自带IOC容器ServiceCollection

    一.  理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二.  接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...

  7. ASP.NET Core 2.1 : 十二.内置日志、使用Nlog将日志输出到文件

    应用离不开日志,虽然现在使用VS有强大的调试功能,开发过程中不复杂的情况懒得输出日志了(想起print和echo的有木有),但在一些复杂的过程中以及应用日常运行中的日志还是非常有用. ASP.NET ...

  8. asp.net core 内置DI容器的一点小理解

    DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IOC). 具体体现为Micorosoft.Extensio ...

  9. 学习笔记:GLSL Core Tutorial – Vertex Shader(内置变量说明)

    1.每个Vertex Shader都有用户定义的输入属性,例如:位置,法线向量和纹理坐标等.Vertex Shaders也接收一致变量(uniform variables). uniform vari ...

  10. .net core 2.0学习记录(三):内置IOC与DI的使用

    本篇的话介绍下IOC和ID的含义以及如何使用.Net Core中的DI. 一.我是这么理解IOC和DI的: IOC:没有用IOC之前是直接new实例来赋值,使用IOC之后是通过在运行的时候根据配置来实 ...

随机推荐

  1. 关于.NET中FileSystemWatcher的一些不被人注意的细节

    .NET 中的FileSystemWatcher可以监控文件系统中的更改.新建.删除和重命名,关于它的事件及属性的讨论有许多,但细节性的具体在什么情况下触发这些事件讨论不多.根据个人测试,总结如下: ...

  2. shell脚本杀进程重启

    #!/bin/bash ID=`ps -ef | grep "abc" | grep -v "$0" | grep -v "grep" | ...

  3. 033-JsonUtils 工具类模板

    模板一:使用的是jackson package cn.e3mall.common.utils; import java.util.List; import com.fasterxml.jackson. ...

  4. PHP之string之str_repeat()函数使用

    str_repeat (PHP 4, PHP 5, PHP 7) str_repeat - Repeat a string str_repeat - 重复一个字符串 Description strin ...

  5. InnoDB存储引擎的表空间文件,重做日志文件

    存储引擎文件:因为MySQL表存储引擎的关系,每个存储引擎都会有自己的文件来保存各种数据.这些存储引擎真正存储了数据和索引等数据. 表空间文件 InnoDB存储引擎在存储设计上模仿了Oracle,将存 ...

  6. 【LeetCode题解】94_二叉树的中序遍历

    目录 [LeetCode题解]94_二叉树的中序遍历 描述 方法一:递归 Java 代码 Python代码 方法二:非递归 Java 代码 Python 代码 [LeetCode题解]94_二叉树的中 ...

  7. IOS折线图二

    上周把项目的折线图给做了下,今天想着把它完善完善,自己设置了不同的数据源来测试,哈哈,还真遇到问题了, 就是给图表设置折点数为0时,视图显示的还是原来的,由于数据为空,应该将其设置为空,所以想着怎么把 ...

  8. 编译android源码遇到错误及其解决方法

    升级ubuntu的14.04后,android的源码又编译错误了,一下是错误说明赫解决方法: 1.make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_ ...

  9. Toolstrip 工具栏控件

    工具栏是另一种获取应用程序主要功能的常用方法,比起菜单更直观.   Tool strip 控件是由system.Windows.forms.Toolstrip类提供的,作用是创建易于自定义的常用工具栏 ...

  10. redis中的发布订阅(Pub/Sub)

    这里使用nodejs的redis模块说明,具体可见https://www.npmjs.com/package/redis,先来通过一个简单的例子了解下redis中的Pub/Sub具体怎么实现吧.. v ...