博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现自己的.NET Core配置Provider之Yaml
阅读量:6611 次
发布时间:2019-06-24

本文共 5682 字,大约阅读时间需要 18 分钟。

YAML是一种更适合人阅读的文件格式,很多大型的项目像Ruby on Rails都选择YAML作为配置文件的格式。如果项目的配置很少,用JSON或YAML没有多大差别。看看rails项目中的配置文件,如果用JSON写试试什么感受吧。

在中已经讲过配置的执行流程,这里不再复述,直接动手。

YamlConfigurationProvider

Yaml是基于文件的,可以直接从FileConfigurationProvider继承,在FileConfigurationProvider实现了监控文件变化并自动重新加载的功能。

internal class YamlConfigurationProvider : FileConfigurationProvider{    public YamlConfigurationProvider(FileConfigurationSource source) : base(source)    {    }    public override void Load(Stream stream)    {        var parser = new YamlConfigurationFileParser();        Data = parser.Parse(stream);    }}

YamlConfigurationParser是解析Yaml文件的核心,后面会介绍。

YamlConfigurationSource

internal class YamlConfigurationSource : FileConfigurationSource{    public override IConfigurationProvider Build(IConfigurationBuilder builder)    {        EnsureDefaults(builder);        return new YamlConfigurationProvider(this);    }}

YamlConfigurationSource实现父类的Build方法,返回YamlConfigurationProvider

AddYamlFile扩展方法

为添加Yaml配置源增加扩展方法。

public static class YamlConfigurationExtensions{    public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path)    {        return AddYamlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false);    }    public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional)    {        return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false);    }    public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)    {        return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange);    }    public static IConfigurationBuilder AddYamlFile(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(Resources.Error_InvalidFilePath, nameof(path));        }        return builder.AddYamlFile(s =>            {                s.FileProvider = provider;                s.Path = path;                s.Optional = optional;                s.ReloadOnChange = reloadOnChange;                s.ResolveFileProvider();            });    }    internal static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, Action
configureSource) { var source = new YamlConfigurationSource(); configureSource(source); return builder.Add(source); }}

YamlConfigurationFileParser

解析Yaml是核心的功能,目前github有开源的C# Yaml项目:和 。SharpYaml Fork自YamlDotNet,但做了不少改进并支持Yaml1.2,不过需要netstandard1.6+。YamlDotNet支持Yaml1.1,需要netstandard1.3+。我选择的YamlSharp。

Yaml可表示三种类型的数据:Scalar(标量,如字符串、布尔值、整数等)、Sequence(序列,如数组)和Mapping(映射,如字典,键值对等)。

关于Yaml可以参考阮一峰老师的。

SharpYaml会把Yaml文件转换为树形结构,然后我们只需要把所有的叶子节点的路径作为字典的键,将叶子节点的值作为字典的值存储起来就可以了。

internal class YamlConfigurationFileParser{    private readonly IDictionary
_data = new SortedDictionary
(StringComparer.Ordinal); private readonly Stack
_context = new Stack
(); private string _currentPath; public IDictionary
Parse(Stream input) { _data.Clear(); _context.Clear(); var yaml = new YamlStream(); yaml.Load(new StreamReader(input)); if (yaml.Documents.Count > 0) { var rootNode = yaml.Documents[0].RootNode; VisitYamlNode("", rootNode); } return _data; } private void VisitYamlNode(string context, YamlNode node) { if (node is YamlScalarNode) { VisitYamlScalarNode(context, (YamlScalarNode)node); } else if (node is YamlMappingNode) { VisitYamlMappingNode(context, (YamlMappingNode)node); } else if (node is YamlSequenceNode) { VisitYamlSequenceNode(context, (YamlSequenceNode)node); } } private void VisitYamlScalarNode(string context, YamlScalarNode node) { EnterContext(context); if (_data.ContainsKey(_currentPath)) { throw new FormatException(string.Format(Resources.Error_KeyIsDuplicated, _currentPath)); } _data[_currentPath] = node.Value; ExitContext(); } private void VisitYamlMappingNode(string context, YamlMappingNode node) { EnterContext(context); foreach (var yamlNode in node.Children) { context = ((YamlScalarNode)yamlNode.Key).Value; VisitYamlNode(context, yamlNode.Value); } ExitContext(); } private void VisitYamlSequenceNode(string context, YamlSequenceNode node) { EnterContext(context); for (int i = 0; i < node.Children.Count; i++) { VisitYamlNode(i.ToString(), node.Children[i]); } ExitContext(); } private void EnterContext(string context) { if (!string.IsNullOrEmpty(context)) { _context.Push(context); } _currentPath = ConfigurationPath.Combine(_context.Reverse()); } private void ExitContext() { if (_context.Any()) { _context.Pop(); } _currentPath = ConfigurationPath.Combine(_context.Reverse()); }}

最后

本项目已在github上开源,地址:

在项目中使用可以执行下面的命令

Install-Package Cxlt.Extensions.Configuration.Yaml

dotnet add package Cxlt.Extensions.Configuration.Yaml

如果这篇文章对你有帮助或有什么问题,欢迎关注“chengxulvtu"公众号。

t_qrcode_for_gh_71d38a91773e_258.jpg

转载于:https://www.cnblogs.com/nianming/p/7097338.html

你可能感兴趣的文章
python(5)字典
查看>>
eBay和PayPal公布分拆细节:双方还将紧密合作
查看>>
Linux CentOS7 两台机器之间免输入密码相互登录(密钥对认证)
查看>>
汇编程序:显示时间(分秒)
查看>>
用createrepo配置Yum本地源
查看>>
wordpress拿WebShell
查看>>
脚本结构和执行
查看>>
warden创建容器的过程
查看>>
【c++】size_t 和 size_type的区别
查看>>
SpringBoot之浅析配置项解析(三)
查看>>
太感谢DUDU拉!有这样的管理员,博客园能不火吗?
查看>>
15.2. switchport trunk encapsulation dot1q 提示 invaild input at^marker.
查看>>
getline函数(精华版)
查看>>
互联网辅助代理IP软件的应用需守牢数据安全的“底线”
查看>>
快速排序及其优化
查看>>
web
查看>>
第七天 结构伪类选择器(一)
查看>>
程序猿生存指南-10 敲定工作
查看>>
JDBC练习题——登录系统
查看>>
代码即设计 | 掘金年度征文
查看>>