Configuration 在ASP.NET Core开发过程中起着很重要的作用,这篇博客主要是理解configuration的来源,以及各种不同类型的configuration source是如何被加载进程序的。
Configuration 的数据源
.NET Core 应用程序的数据源可以有以下几项:
- 设置文件,例如appsettings.json
- 环境变量
- Azure 密钥保管库
- Azure 应用程序配置
- 命令行参数
- 自定义提供程序,已安装或已创建
- 目录文件
- 内存中的 .NET 对象
Configuration 如何被加载
我们发现数据源类型可以千差万别,那cnfiguration 是如何把它们都load进来的呢?
根据上一篇的博客[https://www.cnblogs.com/peppa-nan/p/14953807.html]。
我们知道在CreateDefaultBuilder 的时候,主机会加载进一些环境变量,命令行参数,settings.json 等,这些其实是通过各种不同类型的 Configuration Provider去实现的。
常见的配置提供程序有如下几类:
提供者 | 提供配置从 |
---|---|
Azure Key Vault 配置提供程序 | Azure 密钥保管库 |
Azure 应用程序配置提供程序 | Azure 应用程序配置 |
命令行配置提供程序 | 命令行参数 |
自定义配置提供程序 | 自定义源 |
环境变量配置提供程序 | 环境变量 |
文件配置提供程序 | INI、JSON 和 XML 文件 |
每个文件的密钥配置提供程序 | 目录文件 |
内存配置提供程序 | 内存中的集合 |
用户机密 | 用户配置文件目录中的文件 |
配置源按其配置提供程序的指定顺序读取。在代码中对配置提供程序进行排序,以适应应用程序所需的底层配置源的优先级。
意思是: 我们其实是通过指定configuration provider 的顺序,来决定了各项配置源的优先级别。
默认顺序是:
配置提供程序的典型序列是:
- appsettings.json
-
应用程序设置。
Environment
. json - 用户机密
- 使用环境变量配置提供程序的环境变量。
- 使用命令行配置提供程序的命令行参数。
示例: INI提供程序和JsonFile 提供程序。 以下代码 清除所有配置提供程序并添加几个配置提供程序
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.Sources.Clear(); // 清除已加载的配置程序 var env = hostingContext.HostingEnvironment;
/// 提供 ini file 配置提供程序
config.AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true) .AddIniFile($"MyIniConfig.{env.EnvironmentName}.ini", optional: true, reloadOnChange: true); config.AddEnvironmentVariables(); if (args != null) { config.AddCommandLine(args); } }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
Configuration Provider 源码解析
在调用 AddJsonFile 时,后续通过一系列的重载,其实会call: 代码链接:
https://github.com/dotnet/runtime/blob/99f7bae2a236b1bc5f3a6c35fd29df49f13bd539/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationExtensions.cs#L65
public static IConfigurationBuilder AddJsonFile(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(SR.Error_InvalidFilePath, nameof(path)); } return builder.AddJsonFile(s => { s.FileProvider = provider; //JsonConfigurationProvider.cs s.Path = path; s.Optional = optional; s.ReloadOnChange = reloadOnChange; s.ResolveFileProvider(); }); }
Configuration 自定义实现
我们可以看一个流行的轻量级 配置中心, AgileConfig,这里不重点去讨论整个AgileConfig的实现,只是去关注如何把获取到的 配置加载进configuration 供程序使用;
本质上是继承了 ConfigurationProvider并重写了里面的方法:
public class AgileConfigProvider : ConfigurationProvider { private ConfigClient Client { get; } public AgileConfigProvider(IConfigClient client) { Client = client as ConfigClient; Client.ConfigChanged += (arg) => { this.OnReload(); }; } /// <summary> /// load方法调用ConfigClient的Connect方法,Connect方法会在连接成功后拉取所有的配置。 /// </summary> public override void Load() { Client.ConnectAsync().GetAwaiter().GetResult() ; Data = Client.Data; } }
里面的 ConfigClient 负责维护和server 的websocket 连接,获取server 推送的消息,并且进行心跳检测等等;
ConfigClient的源代码地址在: 【传送门】https://github.com/kklldog/AgileConfig_Client/blob/master/AgileConfig.Client/ConfigClient.cs
和Configuration 的关系不是很大,这里不再展开说;
-------------------------------------------------------------------
会持续整理发布关于后端和NET Core, .NET 的相关学习和认知,欢迎大家一起讨论学习。