我的编程空间,编程开发者的网络收藏夹
学习永远不晚

.Net Core配置Configuration具体实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

.Net Core配置Configuration具体实现

最近又研究了一下.NetCore配置选项的源码实现,又学习到了不少东西。这篇文章先写一下IConfiguration的学习成果,Options的后面补上

核心类

  • ConfigurationBuilder:IConfigurationBuilder  (构建IConfiguration)
  • IConfigurationSource (配置数据来源)
  • IConfigurationProvider (将配置源的原始结构转为为IDictionary<string, string>)
  • ConfigurationRoot:IConfigurationRoot:IConfiguration  (配置根节点)

构建

ConfigurationBuilder

下面是ConfigurationBuilder中的主要代码

可以看到ConfigurationBuilder的主要功能就是配置数据源到集合中

在Build时依次调用IConfigurationSource的Build函数,并将返回的IConfigurationProvider加入到List中

最后用IConfigurationProvider的集合构建一个ConfigurationRoot对象


public IList<IConfigurationSource> Sources = new List<IConfigurationSource>();

public IConfigurationBuilder Add(IConfigurationSource source)
{
    Sources.Add(source);
    return this;
}

public IConfigurationRoot Build()
{
    List<IConfigurationProvider> list = new List<IConfigurationProvider>();
    foreach (IConfigurationSource source in Sources)
    {
        IConfigurationProvider item = source.Build(this);
        list.Add(item);
    }

    return new ConfigurationRoot(list);
}

IConfigurationSource


public class EnvironmentVariablesConfigurationSource : IConfigurationSource
{
    public string Prefix;
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EnvironmentVariablesConfigurationProvider(Prefix);
    }
    public EnvironmentVariablesConfigurationSource()
    {
    }
}
    
   
public class CommandLineConfigurationSource : IConfigurationSource
{
    public IDictionary<string, string> SwitchMappings;
    public IEnumerable<string> Args;
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new CommandLineConfigurationProvider(Args, SwitchMappings);
    }
    public CommandLineConfigurationSource()
    {
    }
}

//JsonConfigurationSource继承自FileConfigurationSource,我这里将其合为一个了
public abstract class JsonConfigurationSource : IConfigurationSource
{
 public IFileProvider FileProvider { get; set; }
 public string Path { get; set; }
 public bool Optional { get; set; }
 public bool ReloadOnChange { get; set; }
 public int ReloadDelay { get; set; } = 250;

 public Action<FileLoadExceptionContext> OnLoadException { get; set; }
    
 public IConfigurationProvider Build(IConfigurationBuilder builder)
 {
  FileProvider = FileProvider ?? builder.GetFileProvider();
  OnLoadException = OnLoadException ?? builder.GetFileLoadExceptionHandler();
  return new JsonConfigurationProvider(this);
 }
    
 public void ResolveFileProvider()
 {
  if (FileProvider == null && !string.IsNullOrEmpty(Path) && System.IO.Path.IsPathRooted(Path))
  {
   string directoryName = System.IO.Path.GetDirectoryName(Path);
   string text = System.IO.Path.GetFileName(Path);
   while (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
   {
    text = System.IO.Path.Combine(System.IO.Path.GetFileName(directoryName), text);
    directoryName = System.IO.Path.GetDirectoryName(directoryName);
   }
   if (Directory.Exists(directoryName))
   {
    FileProvider = new PhysicalFileProvider(directoryName);
    Path = text;
   }
  }
 }
}

上面展示了比较常用的三种ConfigurationSource,代码都比较简单。

也很容易看出来ConfigurationSource的作用就是配置数据源,并不解析数据。

解析数据源的功能由 IConfigurationProvider完成

ConfigurationProvider

下面为IConfigurationProvider接口定义的5个函数


public interface IConfigurationProvider
{
 bool TryGet(string key, out string value);

 void Set(string key, string value);

 IChangeToken GetReloadToken();

 void Load();

 IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
}

ConfigurationProvider是一个抽象类,继承了IConfigurationProvider接口

在新建Provider时一般都会选择直接继承ConfigurationProvider,接下来看一下ConfigurationProvider的几个核心方法


public abstract class ConfigurationProvider : IConfigurationProvider
{
 private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
    
 protected IDictionary<string, string> Data= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

 public virtual bool TryGet(string key, out string value)=>Data.TryGetValue(key, out value);

 public virtual void Set(string key, string value)=>Data[key] = value;

 public virtual void Load(){}

 public IChangeToken GetReloadToken()
 {
  return _reloadToken;
 }
 
 protected void OnReload()
 {
 ConfigurationReloadToken configurationReloadToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
  configurationReloadToken.OnReload();
 }

可以推测出:

  • Load函数负责从源数据读取数据然后给字典Data赋值
  • ConfigurationProvider将数据存储在字典Data中,增加修改都是对字典的操作
  • 每个ConfigurationProvider都会生成一个IChangeToken,在OnReload函数被调用时生成新的Token,并调用原Token的OnReload函数

ConfigurationRoot

在ConfigurationBuilder的Build函数中,我们生成了一个ConfigurationRoot,并给他传递了所有的ConfigrationProvider列表,下面我们看看他用我们的Provider都做了啥吧


private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();

public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
    _providers = providers;
    _changeTokenRegistrations = new List<IDisposable>(providers.Count);
    foreach (IConfigurationProvider p in providers)
    {
        p.Load();
        ChangeToken.OnChange(p.GetReloadToken, 
           delegate{
     var oldToken=Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
                 oldToken.OnReload();
                })
    }
}

public IChangeToken GetReloadToken()=>_changeToken;

上面的代码也对部分地方进行了简化。可以看到ConfigurationRoot在生成时主要就做了两件事

  • 1.调用Provider的Load函数,这会给Provider的Data赋值
  • 2.读取Provider的ReloadToken,每个Provider的Reload事件都会触发ConfigurationRoot自己的ReloadToken的Reload事件

至此配置的数据源构建这块就分析完啦!

查询

常规的配置查询有两种基本方式 :索引器和GetSection(string key)

其余的GetValue等等都是一些扩展方法,本篇文章不对此进行展开研究

索引器

索引器的查询执行的方式是倒叙查询所有的Provider,然后调用Provider的TryGet函数,在查询时重名的Key,最后加入的会生效。

赋值则是依次调用每个Provider的Set函数


public string this[string key]
{
 get
 {
  for (int num = _providers.Count - 1; num >= 0; num--)
  {
   if (_providers[num].TryGet(key, out var value))
   {
    return value;
   }
  }
  return null;
 }
 set
 {
  foreach (IConfigurationProvider provider in _providers)
  {
   provider.Set(key, value);
  }
 }
}

GetSection


public IConfigurationSection GetSection(string key)
{
 return new ConfigurationSection(this, key);
}

public class ConfigurationSection : IConfigurationSection, IConfiguration
{
 private readonly IConfigurationRoot _root;
 private readonly string _path;
 private string _key;
 public string Value
 {
  get
  {
   return _root[Path];
  }
  set
  {
   _root[Path] = value;
  }
 }
 
    //ConfigurationPath.Combine = string.Join(":",paramList);
 public string this[string key]
 {
  get
  {
   return _root[ConfigurationPath.Combine(Path, key)];
  }
  set
  {
   _root[ConfigurationPath.Combine(Path, key)] = value;
  }
 }

 public ConfigurationSection(IConfigurationRoot root, string path)
 {
  _root = root;
  _path = path;
 }

 public IConfigurationSection GetSection(string key)
 {
  return _root.GetSection(ConfigurationPath.Combine(Path, key));
 }

 public IEnumerable<IConfigurationSection> GetChildren()
 {
  return _root.GetChildrenImplementation(Path);
 }

 public IChangeToken GetReloadToken()
 {
  return _root.GetReloadToken();
 }
}

可以看到GetSection会生成一个ConfigurationSection对象

而ConfigurationSection在读取/设置值时实际上就是对查询的Key用:拼接,然后调用IConfigurationRoot(_root)的赋值或查询函数

关于Configuration的配置和读取的知识点大概就是以上这些了,还有更深入的涉及到对象的绑定这一块Get<> Bind<> GetChildren()等,比较难读,要一行一行代码看,以后有时间可能再研究一下

最后贴上一个从数据加载配置源并动态更新的小例子

DBConfiguration示例


 public void Run()
 {
     var builder = new ConfigurationBuilder();
     var dataProvider = new DBDataProvider();
     builder.Sources.Add(new DBConfigurationSource() { DataProvider = dataProvider, ReloadOnChange = true, Table = "config" });
     IConfigurationRoot config = builder.Build();

     Console.WriteLine(config["time"]);
     Task.Run(() =>
              {
                  while (true)
                  {
                      Thread.Sleep(2000);
                      dataProvider.Update("config");
                      Console.WriteLine($"读取配置时间:{config["time"]}");
                  }
              });
     Thread.Sleep(20000);
 }
public class DBConfigurationProvider : ConfigurationProvider
{
    private DBConfigurationSource Source { get; }
    public DBConfigurationProvider(DBConfigurationSource source)
    {
        Source = source;
    }

    public override void Load()
    {
        if (Source.ReloadOnChange)
        {
            ChangeToken.OnChange(() => Source.DataProvider.Watch(Source.Table), LoadData);
        }
        LoadData();
    }

    private void LoadData()
    {
        var data = Source.DataProvider.GetData(Source.Table);
        Load(data);
        OnReload();
    }

    public void Load(Dictionary<string, object> data)
    {
        var dic = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        foreach (var element in data)
        {
            dic.Add(element.Key, element.Value?.ToString());
        }
        base.Data = dic;
    }
}

public class DBConfigurationSource : IConfigurationSource
{
    public DBDataProvider DataProvider { get; set; }
    public string Table { get; set; }
    public bool ReloadOnChange { get; set; }
    public bool Optional { get; set; }

    public DBConfigurationSource()
    {
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new DBConfigurationProvider(this);
    }
}

public class DBDataProvider
{
    private ConcurrentDictionary<string, CancellationTokenSource> tableToken = new ConcurrentDictionary<string, CancellationTokenSource>();
    public DBDataProvider()
    {
    }

    public Dictionary<string, object> GetData(string table)
    {
        switch (table)
        {
            case "config":
                return GetConfig();
        }
        return new Dictionary<string, object>();
    }

    public void Update(string table)
    {
        Console.WriteLine($"更新数据库数据table:{table}");
        if (tableToken.TryGetValue(table, out CancellationTokenSource cts))
        {
            var oldCts = cts;
            tableToken[table] = new CancellationTokenSource();
            oldCts.Cancel();
        }
    }

    private Dictionary<string, object> GetConfig()
    {
        var valueDic = new Dictionary<string, object>();
        valueDic.TryAdd("time", DateTime.Now.ToString());
        valueDic.TryAdd("weather", "windy");
        valueDic.TryAdd("people_number:male", 100);
        valueDic.TryAdd("people_number:female", 150);
        return valueDic;
    }

    public IChangeToken Watch(string table)
    {
        var cts = tableToken.GetOrAdd(table, x => new CancellationTokenSource());
        return new CancellationChangeToken(cts.Token);
    }
}

到此这篇关于.Net Core配置Configuration具体实现的文章就介绍到这了,更多相关.Net Core Configuration内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

.Net Core配置Configuration具体实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

asp.net core configuration配置读取的实现

ASP.NETCore配置读取实现:强大的配置系统,可从配置文件、环境变量等来源加载设置。appsettings.json为默认配置文件,可针对不同环境使用多个配置文件。IConfigurationBuilder构建IConfiguration实例,添加配置来源(IConfigurationSource)。IConfiguration包含所有配置数据,支持索引器和类型化配置。内置配置提供程序加载不同类型数据(如配置文件、环境变量、命令行参数)。可创建自定义配置提供程序集成其他系统。优先级规则决定使用哪个配
asp.net core configuration配置读取的实现
2024-04-02

.Net Core如何配置与实现自动更新

这篇文章给大家分享的是有关.Net Core如何配置与实现自动更新的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。.Net Core 将之前Web.Config中的配置迁移到了appsettings.json文件中
2023-06-19

.net core基于Hangfire+Mysql持久化怎么实现定时任务配置

本篇内容主要讲解“.net core基于Hangfire+Mysql持久化怎么实现定时任务配置”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“.net core基于Hangfire+Mysql持久
2023-06-20

Android获取手机配置信息具体实现代码

代码如下: StringBuilder phoneInfo = new StringBuilder(); phoneInfo.append("Product: " + android.os.Build.PRODUCT + System.ge
2022-06-06

Asp.net core Web Api配置swagger中文的实现

摘要:本文详细阐述了在ASP.NETCoreWebAPI中配置Swagger并将文档翻译为中文的步骤。通过安装Swagger包、添加Swagger中间件和本地化配置,您可以创建交互式的中文API文档。本文还提供了自定义翻译、多语言支持和SwaggerUI主题自定义的扩展技巧。通过配置Swagger和本地化,开发人员可以提高API的可访问性和易用性。
Asp.net core Web Api配置swagger中文的实现
2024-04-02

ASP.NET Core 配置和使用环境变量的实现

前言通常在应用程序开发到正式上线,在这个过程中我们会分为多个阶段,通常会有 开发、测试、以及正式环境等。每个环境的参数配置我们会使用不同的参数,因此呢,在ASP.NET Core中就提供了相关的环境API,方便我们更好的去做这些事情。 环境
2022-06-07

Opensuse中文设置的具体实现方法

本篇内容主要讲解“Opensuse中文设置的具体实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Opensuse中文设置的具体实现方法”吧!Opensuse中文设置的具体实现首先要安装相关
2023-06-16

如何实现core文件自动生成配置文件

这篇文章主要介绍如何实现core文件自动生成配置文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体执行步骤如下:1.编辑环境配置文件,让shell启动时自动设置ulimitvi /etc/profileulimi
2023-06-09

实现core文件自动生成配置文件的方法

本文讲述了实现core文件自动生成的配置方法,具体执行步骤如下: 1.编辑环境配置文件,让shell启动时自动设置ulimitvi /etc/profile ulimit -c unlimited > /dev/null 2>&12.更改c
2022-06-04

Linux测试工具netstat如何配置及实现

这篇文章主要介绍Linux测试工具netstat如何配置及实现,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!netstat命令是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络
2023-06-16

android预置默认的语音信箱号码具体实现

有些SIM卡在出厂时并没有预置VoiceMail number,但运营商又要求能够根据PLMN去自适应的从手机中读取到预设的VM number。在此介绍以xml的方式预置VM number的方法,以及如何允许用户去修改并能够记住用户的选择。
2022-06-06

Linux测试工具route的配置及实现方法

本篇内容主要讲解“Linux测试工具route的配置及实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux测试工具route的配置及实现方法”吧!本文是介绍管理Linux系统网络性能
2023-06-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录