YAML是一種更適合人閱讀的文件格式,很多大型的項(xiàng)目像Ruby on Rails都選擇YAML作為配置文件的格式。如果項(xiàng)目的配置很少,用JSON或YAML沒(méi)有多大差別??纯磖ails項(xiàng)目中的配置文件,如果用JSON寫(xiě)試試什么感受吧。

在《實(shí)現(xiàn)自己的.NET Core配置Provider之EF》中已經(jīng)講過(guò)配置的執(zhí)行流程,這里不再?gòu)?fù)述,直接動(dòng)手。

YamlConfigurationProvider

Yaml是基于文件的,可以直接從FileConfigurationProvider繼承,在FileConfigurationProvider實(shí)現(xiàn)了監(jiān)控文件變化并自動(dòng)重新加載的功能。

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文件的核心,后面會(huì)介紹。

YamlConfigurationSource

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

YamlConfigurationSource實(shí)現(xiàn)父類(lèi)的Build方法,返回YamlConfigurationProvider

AddYamlFile擴(kuò)展方法

為添加Yaml配置源增加擴(kuò)展方法。

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有開(kāi)源的C# Yaml項(xiàng)目:YamlDotNetSharpYaml 。SharpYaml Fork自YamlDotNet,但做了不少改進(jìn)并支持Yaml1.2,不過(guò)需要netstandard1.6+。YamlDotNet支持Yaml1.1,需要netstandard1.3+。我選擇的YamlSharp。

Yaml可表示三種類(lèi)型的數(shù)據(jù):Scalar(標(biāo)量,如字符串、布爾值、整數(shù)等)、Sequence(序列,如數(shù)組)和Mapping(映射,如字典,鍵值對(duì)等)。

關(guān)于Yaml可以參考阮一峰老師的《YAML 語(yǔ)言教程》

SharpYaml會(huì)把Yaml文件轉(zhuǎn)換為樹(shù)形結(jié)構(gòu),然后我們只需要把所有的葉子節(jié)點(diǎn)的路徑作為字典的鍵,將葉子節(jié)點(diǎn)的值作為字典的值存儲(chǔ)起來(lái)就可以了。

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());
    }
}

最后

本項(xiàng)目已在github上開(kāi)源,地址:https://github.com/chengxulvtu/Cxlt.Extensions.Configuration

在項(xiàng)目中使用可以執(zhí)行下面的命令

Install-Package Cxlt.Extensions.Configuration.Yaml

dotnet add package Cxlt.Extensions.Configuration.Yaml

如果這篇文章對(duì)你有幫助或有什么問(wèn)題,歡迎關(guān)注“chengxulvtu"公眾號(hào)。

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

作者:BobTian
出處http://nianming.cnblogs.com/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 
歡迎訪問(wèn)我的個(gè)人博客:程序旅途 
萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

http://www.cnblogs.com/nianming/p/7097338.html