该组件有四个类
JsonConfigurationExtensions
JsonConfigurationSource
JsonConfigurationFileParser
JsonConfigurationProvider
这四个类相互合作,职责明确,共同将JSON类型的配置加载到内存中,供相应的系统使用。
JsonConfigurationFileParser
该类是一个内部类,拥有一个私有的构造方法,意味着该类无法在其他地方进行实例化,只能在自己内部使用。它只有一个公共方法,并且是静态的,如下所示
1: public static IDictionary<string, string> Parse(Stream input) => new JsonConfigurationFileParser().ParseStream(input);
该方法通过读取输入数据流,将其转化为字典类型的配置数据,该字典类型是SortedDictionary类型的,并且不区分大小写,此处需要注意。这也呼应了之前所说的.NET Core Configuration对外使用的时候,都是以字典方式去提供给外界使用的。
那么,这个类是如何将数据流转化为JSON的呢,我们继续阅读源码
1: private IDictionary<string, string> ParseStream(Stream input)
2: {
3: _data.Clear();
4:
5: using (var reader = new StreamReader(input))
6: using (JsonDocument doc = JsonDocument.Parse(reader.ReadToEnd(), new JsonReaderOptions { CommentHandling = JsonCommentHandling.Skip }))
7: {
8: if (doc.RootElement.Type != JsonValueType.Object)
9: {
10: throw new FormatException(Resources.FormatError_UnsupportedJSONToken(doc.RootElement.Type));
11: }
12: VisitElement(doc.RootElement);
13: }
14:
15: return _data;
16: }
通过源码,我们知道,此处使用了JsonDocument处理StreamReader数据,JsonDocument又是什么呢,通过命名空间我们知道,它位于System.Text.Json中,这是.NET Core原生的处理JSON的组件,有兴趣的朋友可以去翻翻MSDN或者GitHub查找相关资料。此处不做过多说明。
VisitElement方法主要是遍历JsonElement.EnumerateObject()方法中的对象集合,此处采用Stack实例进行数据安全方面的控制。其中VisitValue是一个在处理json时相当全面的方法,说它全面是因为它考虑到了JSON值的几乎所有类型:
JsonValueType.Object
JsonValueType.Array
JsonValueType.Number
JsonValueType.String
JsonValueType.True
JsonValueType.False
JsonValueType.Null
当然,该方法,并不会很傻的处理每一种类型,主要是针对Object和Array类型进行了递归遍历,以便在诸如Number、String等的简单类型时跳出递归,并存放到字典中,需要再次强调的是,存放在字典中的值是以String类型存储的。
至此,JsonConfigurationFileParser完成了从文件读取内容并转化为键值对的工作。
JsonConfigurationSource
这个类比较简单,因为继承自FileConfigurationSource,如前文所说,FileConfigurationSource类已经做了初步的实现,只提供了一个Build方法交给子类去重写。其返回值是JsonConfigurationProvider实例。
1: ///
2: /// Represents a JSON file as an .
3: ///
4: public class JsonConfigurationSource : FileConfigurationSource
5: {
6: ///
7: /// Builds the for this source.
8: ///
9: /// The .
10: /// A
11: public override IConfigurationProvider Build(IConfigurationBuilder builder)
12: {
13: EnsureDefaults(builder);
14: return new JsonConfigurationProvider(this);
15: }
16: }
此处的EnsureDefaults()方法,主要是设置FileProvider实例以及指定加载类型的异常处理方式。
JsonConfigurationProvider
这个类也很简单,它继承于FileConfigurationProvider,FileConfigurationProvider本身也已经通用功能进行了抽象实现,先看一下这个类的源码
1: ///
2: /// A JSON file based .
3: ///
4: public class JsonConfigurationProvider : FileConfigurationProvider
5: {
6: ///
7: /// Initializes a new instance with the specified source.
8: ///
9: /// The source settings.
10: public JsonConfigurationProvider(JsonConfigurationSource source) : base(source) { }
11:
12: ///
13: /// Loads the JSON data from a stream.
14: ///
15: /// The stream to read.
16: public override void Load(Stream stream)
17: {
18: try {
19: Data = JsonConfigurationFileParser.Parse(stream);
20: } catch (JsonReaderException e)
21: {
22: throw new FormatException(Resources.Error_JSONParseError, e);
23: }
24: }
25: }
其构造函数的传入参数类型是JsonConfigurationSource,这和JsonConfigurationSource.Build()方法中的return new JsonConfigurationProvider(this)代码片段相呼应。
JsonConfigurationProvider所重写的方法,调用的是JsonConfigurationFileParser.Parse(stream)方法,所以该类显得非常的轻量。
JsonConfigurationExtensions
这个方法,大家就更熟悉了,我们平时所使用的AddJsonFile()方法,就是在这个扩展类中进行扩展的,其返回值是IConfigurationBuilder类型,其核心方法源码如下所示
1: ///
2: /// Adds a JSON configuration source to .
3: ///
4: /// The to add to.
5: /// The to use to access the file.
6: /// Path relative to the base path stored in
7: /// of .
8: /// Whether the file is optional.
9: /// Whether the configuration should be reloaded if the file changes.
10: /// The .
11: public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
12: {
13: if (builder == null)
14: {
15: throw new ArgumentNullException(nameof(builder));
16: }
17: if (string.IsNullOrEmpty(path))
18: {
19: throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
20: }
21:
22: return builder.AddJsonFile(s =>
23: {
24: s.FileProvider = provider;
25: s.Path = path;
26: s.Optional = optional;
27: s.ReloadOnChange = reloadOnChange;
28: s.ResolveFileProvider();
29: });
30: }
不过,大家不要看这个方法的代码行数很多,就认为,其他方法都重载与该方法,其实该方法重载自
1: ///
2: /// Adds a JSON configuration source to .
3: ///
4: /// The to add to.
5: /// Configures the source.
6: /// The .
7: public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action configureSource)
8: => builder.Add(configureSource);
这个方法最终调用的还是IConfigurationBuilder.Add()方法
总结
通过介绍以上JSON Configuration组件的四个类,我们知道了,该组件针对JSON格式的文件的处理方式,不过由于其实文件型配置,其抽象实现已经在文件型配置扩展实现。
从这里,我们可以学习一下,如果有一天我们需要扩展远程配置,比如Consul、ZK等,我们也可以考虑并采用这种架构的设计方式。另外在JSON Configuration组件中,.NET Core将专有型功能方法的处理进行了聚合,并聚焦关注点的方式也值得我们学习。
最后JsonConfigurationFileParser中给了我们一种关于Stream转换成JSON的实现,我们完全可以把这个类当成工具类去使用。
深圳网站建设 https://www.sz886.com/