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

《实现自己的.NET Core配置Provider之EF》中已经讲过配置的执行流程,这里不再复述,直接动手。

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<YamlConfigurationSource> configureSource)
{
var source = new YamlConfigurationSource();
configureSource(source);
return builder.Add(source);
}
}

YamlConfigurationFileParser

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

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

关于Yaml可以参考阮一峰老师的《YAML 语言教程》

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

internal class YamlConfigurationFileParser
{
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.Ordinal);
private readonly Stack<string> _context = new Stack<string>();
private string _currentPath; public IDictionary<string, string> 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上开源,地址:https://github.com/chengxulvtu/Cxlt.Extensions.Configuration

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

Install-Package Cxlt.Extensions.Configuration.Yaml

dotnet add package Cxlt.Extensions.Configuration.Yaml

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

实现自己的.NET Core配置Provider之Yaml的更多相关文章

  1. 实现自己的.NET Core配置Provider之EF

    <10分钟就能学会.NET Core配置>里详细介绍了.NET Core配置的用法,另外我还开源了自定义的配置Provider:EF配置Provider和Yaml配置Provider.本文 ...

  2. 10分钟就能学会的.NET Core配置

    .NET Core为我们提供了一套用于配置的API,它为程序提供了运行时从文件.命令行参数.环境变量等读取配置的方法.配置都是键值对的形式,并且支持嵌套,.NET Core还内建了从配置反序列化为PO ...

  3. 【转】10分钟就能学会的.NET Core配置

    .NET Core为我们提供了一套用于配置的API,它为程序提供了运行时从文件.命令行参数.环境变量等读取配置的方法.配置都是键值对的形式,并且支持嵌套,.NET Core还内建了从配置反序列化为PO ...

  4. SQLite EF Core Database Provider

    原文链接 This database provider allows Entity Framework Core to be used with SQLite. The provider is mai ...

  5. Net core学习系列(九)——Net Core配置

    一.简介 NET Core为我们提供了一套用于配置的API,它为程序提供了运行时从文件.命令行参数.环境变量等读取配置的方法.配置都是键值对的形式,并且支持嵌套,.NET Core还内建了从配置反序列 ...

  6. 关于Asp.net core配置信息读取的源码分析梳理

    概述 我们都知道asp.net core配置信息的读取离不开IConfigurationSource和IConfigurationProvider这两个类,ConfigurationSource可以提 ...

  7. ASP.NET Core配置Kestrel 网址Urls

    ASP.NET Core中如何配置Kestrel Urls呢,大家可能都知道使用UseUrls() 方法来配置. 今天给介绍全面的ASP.NET Core 配置 Urls,使用多种方式配置Urls.让 ...

  8. net core体系-web应用程序-4net core2.0大白话带你入门-4asp.net core配置项目访问地址

    asp.net core配置访问地址  .net core web程序,默认使用kestrel作为web服务器. 配置Kestrel Urls有四种方式,我这里只介绍一种.其它方式可自行百度. 在Pr ...

  9. .net core 配置

    .net core 配置包括很多种 例如内存变量.命令行参数.环境变量以及物理文件配置和自定义配置 物理文件配置主要有三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfi ...

随机推荐

  1. Spring AOP的切入点表达式

    在spring Aop中要使用AspectJ的切点表达式语言来定义切点.Spring仅仅支持AspectJ切点指示器的一个子集.下表列出了Spring AOP所支持的AspectJ切点指示器. 在Sp ...

  2. 【转】MyISAM和InnoDB 区别

    InnoDB和MyISAM是MySQL最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调 ...

  3. 写给Android App开发人员看的Android底层知识(1)

    这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...

  4. liunx命令2

    查看系统和bios硬件时间 [root@localhost ~]# date '+%y- %m- %d %H:%M' 17- 05- 15 02:57[root@localhost ~]# date ...

  5. 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

    树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n ...

  6. 【JavaScript OPP基础】---新手必备

    今天和大家分享一下近期整理的有关JavaScriptOPP的基础知识~~~我们一起来学习一下-- JavaScriptOPP基础 一.面向对象编程OOP1.语言的分类:面向机器:汇编语言面向过程:C语 ...

  7. 备忘录《一》基于cookie使用拦截器实现客户每次访问自登陆一次

    原创声明:本文为本人原创作品,绝非他处摘取,转载请联系博主 相信大家在各大网站都会遇到,登录时,在登录框出现下次免登陆/一个月免登陆的类似选项,本次博文就是讲解如何实现,在这记录一下,也算是做个备忘录 ...

  8. 关于Python编码,超诡异的,我也是醉了

    Python的编码问题,真是让人醉了.最近碰到的问题还真不少.比如中文文件名.csv .python对外呈现不一致啊,感觉好不公平. 没图说个JB,下面立马上图.   我早些时候的其他脚本,csv都是 ...

  9. 开涛spring3(2.2) - IoC 容器基本原理及其helloword

    2.2.1  IoC容器的概念 IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IoC ...

  10. set集合(一)

    set 叫做集合  作用:  去重(去除重复) 举例-- >>> name_list = ['alben','nichole','lucy','andy','tom','alben' ...