zoukankan      html  css  js  c++  java
  • Asp.Net Core- 配置组件详解

    我们之前写的配置都是放置在配置文件Web.config或者app.config中,.net core提供了全新的配置方式,可以直接写在内存中或者写在文件中。

    .Net Core的配置API主要体现在3个类中Configuration、ConfigurationBuilder、ConfigurationProvider中。

    配置文件其实就是一个键值对。Configuration以树形结构描述了这些键值对之间的关系。我们的配置文件比如project.json是怎么转换成Configuration树形结构的呢?

    Microsoft.Extensions.Options这个命名空间下的类提供了文件向Configuration的转换。

    一、配置文件分为3种结构

    1. 逻辑结构:就是我们看到的结构,树形结构。

    2. 原始结构:就是文件本身的结构,比如xml、json等等。

    3. 物理结构:介于两者之间的结构,键值对。

    配置组件的最终目的就是把原始结构转化成逻辑结构,在具体转换过程中,先找到对应的ConfigurationProvider转化为物理结构数据字典,然后再由ConfigurationBuilder转化为逻辑结构Configuration对象。

    二、Configuration

    Configuration对象泛指继承自接口IConfiguration的对象。这个接口如下:

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using Microsoft.Extensions.Primitives;
    
    using System;
    
    using System.Collections.Generic;
    
    using System.Reflection;
    
    public interface IConfiguration
    
    {
    
    IEnumerable<IConfigurationSection> GetChildren();
    
    IChangeToken GetReloadToken();
    
    IConfigurationSection GetSection(string key);
    
    string this[string key] { get; set; }
    
    }
    
    }
    View Code

    这个接口GetChildren表示所有的ConfigurationSection对象;GetSection根据key值得到ConfigurationSection对象。

    继承自这个接口的对象分别是ConfigurationRoot和ConfigurationSection,分别表示配置的根节点和叶子节点。

    ConfigurationRoot还继承自接口IConfigurationRoot接口,代码如下:

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using System;
    
    public interface IConfigurationRoot : IConfiguration
    
    {
    
    void Reload();
    
    }
    
    }
    View Code

    这个接口只有一个方法Reload重新加载,当调用这个方法的时候,在这棵树下的所有的节点都会重新加载。

    ConfigurationSection还继承自IConfigurationSection,代码如下:

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using System;
    
    public interface IConfigurationSection : IConfiguration
    
    {
    
    string Key { get; }
    
    string Path { get; }
    
    string Value { get; set; }
    
    }
    
    }
    View Code

    Key表示父节点的名称;Path表示当前节点的路径,用“:”隔开;Value只有在叶子节点才有值,非叶子节点返回Null。

    三、ConfigurationProvider

    ConfigurationProvider对象泛指实现了接口IConfigurationProvider的对象。

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using Microsoft.Extensions.Primitives;
    
    using System;
    
    using System.Collections.Generic;
    
    using System.Runtime.InteropServices;
    
    public interface IConfigurationProvider
    
    {
    
    IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
    
    IChangeToken GetReloadToken();
    
    void Load();
    
    void Set(string key, string value);
    
    bool TryGet(string key, out string value);
    
    }
    
    }
    View Code

    而继承自这个接口的是一个抽象类ConfigurationProvider,代码如下:

    public abstract class ConfigurationProvider : IConfigurationProvider
    
    {
    
    // Fields
    
    private ConfigurationReloadToken _reloadToken;
    
    // Methods
    
    protected ConfigurationProvider();
    
    public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
    
    public IChangeToken GetReloadToken();
    
    public virtual void Load();
    
    protected void OnReload();
    
    private static string Segment(string key, int prefixLength);
    
    public virtual void Set(string key, string value);
    
    public virtual bool TryGet(string key, out string value);
    
    // Properties
    
    protected IDictionary<string, string> Data { get; set; }
    
    }
    View Code

    因为这个类的最终目的就是转化为数据字典,所以,这个类的方法大部分都是针对数据字典,方法的参数中都有key值。

    不同的数据源都是继承自这个抽象类,重写自己的方法。

    Load方法从数据源加载数据,针对不同的数据源子类可以重写;TryGet根据key值获取数据值;Set方法设置数据值,因为这个类的主要功能是从数据源读取数据转化为数据字典,所以Set的值只保存在内存中。

    四、ConfigurationBuilder

    泛指实现了接口IConfigurationBuilder的对象。他的作用就是根据ConfigurationProvider提供的数据字典,把数据字典转化为ConfigurationRoot对象。接口如下:

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using System.Collections.Generic;
    
    public interface IConfigurationBuilder
    
    {
    
    IConfigurationBuilder Add(IConfigurationSource source);
    
    IConfigurationRoot Build();
    
    Dictionary<string, object> Properties { get; }
    
    IEnumerable<IConfigurationSource> Sources { get; }
    
    }
    
    }
    View Code

    主要通过Build方法实现把数据字典转化为ConfigurationRoot。

    无论是ConfigurationRoot还是ConfigurationSection本身都没有封装任何形式的对配置的读取操作,所有的读取操作都是在ConfigurationProvider对象中。

    在ConfigurationRoot和ConfigurationSection组成的树形结构中,并没有在代码中直接保存这种结构,而是每个ConfigurationSection中都有一个ConfigurationRoot对象,直接是对根节点的引用。而只有根节点中有对ConfigurationProvider的调用。也就是在每个叶子节点中都有一个对于根节点的引用。这样当我们想要获取某个节点的具体值时,先找到根节点,再通过根节点找到ConfigurationProvider,通过ConfigurationProvider对象获取配置值。

    还有一个对象ConfigurationPath,主要封装对树层级结构的计算,代码如下:

    namespace Microsoft.Extensions.Configuration
    
    {
    
    using System;
    
    using System.Collections.Generic;
    
    public static class ConfigurationPath
    
    {
    
    public static readonly string KeyDelimiter = ":";
    
    public static string Combine(IEnumerable<string> pathSegments)
    
    {
    
    if (pathSegments == null)
    
    {
    
    throw new ArgumentNullException("pathSegments");
    
    }
    
    return string.Join(KeyDelimiter, pathSegments);
    
    }
    
    public static string Combine(params string[] pathSegments)
    
    {
    
    if (pathSegments == null)
    
    {
    
    throw new ArgumentNullException("pathSegments");
    
    }
    
    return string.Join(KeyDelimiter, pathSegments);
    
    }
    
    public static string GetParentPath(string path)
    
    {
    
    if (!string.IsNullOrEmpty(path))
    
    {
    
    int length = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase);
    
    if (length != -1)
    
    {
    
    return path.Substring(0, length);
    
    }
    
    }
    
    return null;
    
    }
    
    public static string GetSectionKey(string path)
    
    {
    
    if (!string.IsNullOrEmpty(path))
    
    {
    
    int num = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase);
    
    if (num != -1)
    
    {
    
    return path.Substring(num + 1);
    
    }
    
    }
    
    return path;
    
    }
    
    }
    
    }
    View Code

    Combine方法实现把路径连接成一个完整的路径。

    以上对象之间的关系图如下:

    http://images2015.cnblogs.com/blog/19327/201604/19327-20160419220618335-900092396.png

    综上,配置模块的最终目的是要把原始的配置文件比如:json、xml转换为一个ConfigurationRoot对象,这个对象是一个树形结构,下边是ConfigurationSection对象。当我们要获取某个配置时,通过ConfigurationRoot的ConfigurationProvider获取,每个ConfigurationSection都有一个对于根节点的引用。

    后记:当需要读取一个配置文件的时候,调用ConfigurationBuilder的build方法把文件内容转换为ConfigurationRoot对象,在这个方法执行过程中,会调用根据配置文件的不同调用相关的ConfigurationProvider ,然后调用ConfigurationProvider的Load方法,把配置文件转换成数据字典;然后再回到ConfigurationBuilder中把数据字典转化为ConfigurationRoot。

    参考链接:http://www.cnblogs.com/artech/p/asp-net-core-config-01.html

  • 相关阅读:
    A Philosophy of Software Design
    数据密集型应用-笔记
    百万行超大csv文件如何快速导入mysql
    spring framework源码maven构建版及一点经验总结
    Mac上给应用设置与系统语言不一样的语言设置
    转:how-to-run-junit-springjunit4classrunner-with-parametrized(spring-test如何与junit的Parameterized结合)
    学习数据结构和算法的框架思维(转载)
    进程与线程(廖雪峰进程和线程学习笔记)
    自然语言信息提取结构
    最大熵模型
  • 原文地址:https://www.cnblogs.com/zh1990/p/5681280.html
Copyright © 2011-2022 走看看