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. Servlet的线程安全

    Servlet的线程安全 一.什么是Servlet的线程安全 1.在Servlet的整个生命周期中,构造方法只被执行一次.也就是说,在Servlet的整个生命周期中,只存在一个Servlet实例对象. ...

  2. 吕鑫VC6.0-VS2015 全套C/C++、MFC新手实战入门教程、Linux视频教程 最好的基础入门教程没有之一

    本课程包括:[1]C语言(1个月)[2]C++语法与数据结构(1个月)) [3]MFC项目开发(1个月)[4]Linux项目开发(1个月)往届的授课视频都已经上传到百度网盘,请同学们按照视频教程提前掌 ...

  3. jgs--多线程和synchronized

    多线程 多线程是我们开发人员经常提到的一个名词.为什么会有多线程的概念呢?我们的电脑有可能会有多个cpu(或者CPU有多个内核)这就产生了多个线程.对于单个CPU来说,由于CPU运算很快,我们在电脑上 ...

  4. Git总结笔记3-把本地仓库推送到github

    说明:此笔记在centos 7 上完成 1.配置公钥 [root@kangvcar ~]# ssh-keygen -t rsa -C "kangvcar@126.com" [roo ...

  5. Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6869133.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)——My ...

  6. linux系统管理--查看进程

    关于进程的查看,大家都不会陌生 ,主要是ps和pstree命令. ps  aux    查看系统中所有进程,使用BSD操作系统格式.(注意:不是ps -aux) 执行结果 USER :该进程是由哪个用 ...

  7. 使用r.js优化静态资源

    r.js主要功能:优化项目的静态资源.可以简化压缩代码,减少体积.指定模块将多个组件合并为一个文件,减少HTTP请求数量.具体使用步骤如下: 先把 r.js 文件放到项目根目录,再于项目根目录内新建一 ...

  8. mybaties 缓存

    http://www.cnblogs.com/zemliu/archive/2013/08/05/3239014.html http://www.cnblogs.com/xdp-gacl/p/4270 ...

  9. 第 7 章 MySQL 数据库锁定机制

      前言: 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一.本章将对 MySQ ...

  10. 开涛spring3(9.2) - Spring的事务 之 9.2 数据库事务概述

    9.2.1  概述 Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口 PlatformTransactionManager,从而能支持 ...