.NET Core中配置Configuration的学习指南
作者:caoruipeng
什么是配置
.NET中的配置,本质上就是key-value键值对,并且key和value都是字符串类型。
在.NET中提供了多种配置提供程序来对不同的配置进行读取、写入、重载等操作,这里我们以为.NET 的源码项目为例,来看下.NET中的配置主要是有那些类库。下面这个截图是.NET 源码中和配置相关的所有类库,所有配置相关的类库都是都是以Microsoft.Extensions.Configuration开头的。
貌似很多,没关系我们来简单理解一下。
类库名称 | 类库作用 |
---|---|
1、Microsoft.Extensions.Configuration.Abstractions | 定义配置相关的接口,其他所有配置类库都必须引用这个类库 |
2、Microsoft.Extensions.Configuration | Microsoft.Extensions.Configuration.Abstractions类库的简单实现 |
3、配置提供程序:Microsoft.Extensions.Configuration.CommandLine | 基于命令行的配置提供程序,负责对命令行的配置进行读写、载入、重载等操作。 |
4、配置提供程序:Microsoft.Extensions.Configuration.EnvironmentVariables | 基于环境变量的配置提供程序,负责对环境变量的配置进行读写、载入、重载等操作 |
5、配置提供程序:Microsoft.Extensions.Configuration.FileExtensions | 基于的文件提供程序的基类库,文件提供程序包括基于Json文件、Ini文件、Xml文件或者自定义文件等。 |
6、配置提供程序:Microsoft.Extensions.Configuration.Json | 基于Json文件的配置提供程序程序,负责从Json文本文件中对配置读写、载入、重载等操作。 |
7、配置提供程序:Microsoft.Extensions.Configuration.Ini | 基于Ini文件的配置提供程序,负责从Ini文件中对配置进行读写、载入、重载等操作。 |
8、配置提供程序:Microsoft.Extensions.Configuration.UserSecrets | 基于UserSecrets的配置提供程序,这个本质上也是一种基于Json文件类型的配置程序。主要用于管理应用机密 |
9、Microsoft.Extensions.Configuration.Binder | 负责将key-value键值对的配置列表绑定到指定的C#实体类上,方便程序使用。 |
从上面可以看到,主要有四个类库:第1个类库Abstractions
负责定义配置的一些接口,第2个类库Configuration
负责定义配置的简单实现。第3到第8个类库都是具体的配置提供程序,第9个类库Binder
负责将配置绑定到指定的的Model,方便程序使用。
配置提供程序,.NET中有多个类库提供程序,每个类库提供程序都是以单独的类库向外提供,基本上每个类库就是三个文件,分别是ConfigurationExtensions.cs、ConfigurationProvider.cs和ConfigurationSource.cs,这三个类分别表示配置的扩展方法、配置提供程序和配置源。配置源用于生成配置提供程序。
在第2个类库中,微软帮助我们实现了一个基于类库的配置提供程序,我们在列表中没有单独列举这个类库提供程序。
配置源IConfigurationSource
配置源表示一个单独的配置集合,可以表示来自内存的配置源、来自Json文件的配置源。但是配置源不直接提供对配置的访问操作,它只有一个接口Build
,该接口一个具体的配置提供程序IConfigurationProvider
,每个配置提供程序负责对配置的读取、写入、载入配置、重载配置等访问操作。
public interface IConfigurationSource { IConfigurationProvider Build(IConfigurationBuilder builder); }
配置提供程序IConfigurationProvider
配置提供程序负责实现配置的设置、读取、重载等功能,并以键值对形式提供配置。
public interface IConfigurationProvider { //读取配置 bool TryGet(string key, out string? value); //修改配置 void Set(string key, string? value); //获取重载配置的Token IChangeToken GetReloadToken(); //载入配置 void Load(); //获取指定父路径下的直接子节点Key,然后 Concat(earlierKeys) 一同返回 IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string? parentPath); }
配置构建者IConfigurationBuilder
上面的IConfigurationSource和IConfigurationProvider分别表示一种数据源和对一种数据源进行读写操作。但是一个程序的配置可能来自很多地方,可能一部分配置来自环境变量、一部分配置来自文件等等。这个时候IConfigurationBuilder配置构建者就诞生了,IConfigurationBuilder接口维护了多个配置源,并提供一个Build方法生成一个统一的配置IConfigurationRoot
来统一对整个程序的配置进行读取、写入、重载等操作。但是这里大家注意,IConfigurationRoot
对配置的访问,本质上还是通过配置提供程序IConfigurationProvider
来进行的。
假设,当我们查找一个Key为Name的配置,IConfigurationRoot
内部会遍历所有Sources
属性生成的IConfigurationProvider
,然后依次调用IConfigurationProvider
的TryGet来获取Name的具体配置数据。
public interface IConfigurationBuilder { //保存Build的一些公开的字典属性,有需要的化可以使用该字段存放一些变量 IDictionary<string, object> Properties { get; } //来自多个地方的配置源集合 IList<IConfigurationSource> Sources { get; } //向Sources属性中添加一个配置源 IConfigurationBuilder Add(IConfigurationSource source); //基于所有配置源生成一个全局的配置,供程序读写,一般我们都是用这个接口对配置进行读写。 IConfigurationRoot Build(); }
配置构建者实现类ConfigurationBuilder
在具体的配置构建者的Build方法中,我们可以看到,它依次调用IConfigurationProvider
的Buid方法生成多个配置提供程序IConfigurationProvider
,然后将所有的配置提供程序providers
传给了ConfigurationRoot
。ConfigurationRoot
正是调用providers
的一系列方法实现对配置的读取、写入、重载等操作。
public class ConfigurationBuilder : IConfigurationBuilder { private readonly List<IConfigurationSource> _sources = new(); public IList<IConfigurationSource> Sources => _sources; public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>(); public IConfigurationBuilder Add(IConfigurationSource source) { ThrowHelper.ThrowIfNull(source); _sources.Add(source); return this; } public IConfigurationRoot Build() { var providers = new List<IConfigurationProvider>(); foreach (IConfigurationSource source in _sources) { IConfigurationProvider provider = source.Build(this); providers.Add(provider); } return new ConfigurationRoot(providers); } }
配置接口IConfiguration
这个接口就是最核心的配置接口,提供了对配置的读取、写入、重载等操作,它的实现类是ConfigurationRoot
,上面我们已经介绍过,IConfiguration
本身还是通过各个配置提供程序对配置进行访问操作。
public interface IConfiguration { //获取或设置配置 string? this[string key] { get; set; } //获取指定key的配置子节点 IConfigurationSection GetSection(string key); //获取当前配置的直接子节点列表 IEnumerable<IConfigurationSection> GetChildren(); //当配置发生变更时的token IChangeToken GetReloadToken(); }
配置接口IConfigurationRoot
IConfigurationRoot其实是配置的根接口,该接口有个最重要的属性Providers
负责保存所有的配置提供程序,IConfiguration
对配置的访问,就是通过遍历这个Providers
来访问的。
public interface IConfigurationRoot : IConfiguration { //强制重载所有配置 void Reload(); //所有配置提供程序 IEnumerable<IConfigurationProvider> Providers { get; } }
实现自定义配置提供程序
实现自定义配置提供程序,其实只需要实现三个类就可以,一个是配置源、一个是配置提供程序、一个是针对当前配置的扩展方法。第三个类可有可无,不过我们一般都要实现。我们来参考下基于命令行的配置提供程序类库的文件。
接下来,我们来实现一个基于数据库的配置提供程序,分别实现配置源DataBaseConfigurationSource
、配置提供程序DataBaseConfigurationExtensions
和扩展方法类DataBaseConfigurationExtensions
,当然在这里我们只做对应的演示,没有实现具体的配置方法。
public class DataBaseConfigurationSource : IConfigurationSource { public IConfigurationProvider Build(IConfigurationBuilder builder) { return new DataBaseConfigurationProvider(); } } public class DataBaseConfigurationProvider : ConfigurationProvider { public override void Load() { base.Load(); //读取数据库配置 } } public static class DataBaseConfigurationExtensions { public static IConfigurationBuilder AddDb(this IConfigurationBuilder configurationBuilder) { configurationBuilder.Sources.Add(new DataBaseConfigurationSource()); return configurationBuilder; } }
调用自定义配置程序
static void Main(string[] args) { var builder = new ConfigurationBuilder() .AddDb() .Build(); var value = builder["key"]; }
实战
基于内存的配置程序
基于内存的配置程序主要是在内存中维护了一个Key-Value键值对。
static void MemoryConfig() { List<KeyValuePair<string, string?>>? initialData = new List<KeyValuePair<string, string?>>(); initialData.Add(new KeyValuePair<string, string?>("name", "tom")); IConfigurationRoot configuration = new ConfigurationBuilder() .AddInMemoryCollection(initialData) .Build(); Console.WriteLine("name:" + configuration["name"]); }
调用如下:
static void Main(string[] args) { MemoryConfig(); }
基于现有的配置提供程序
这个配置提供程序用的相对较少,是微软在Microsoft.Extensions.Configuration类库中默认实现的一个配置提供程序,它可以把已经存在的配置IConfigurationRoot
封装成一个配置提供程序。如果需要对针对现有配置快速Copy出一个新配置的话,可以使用这个配置提供程序。
static void ChainedConfig() { List<KeyValuePair<string, string?>>? initialData = new List<KeyValuePair<string, string?>>(); initialData.Add(new KeyValuePair<string, string?>("name", "tom")); //初始化一个已有的配置 IConfigurationRoot configuration = new ConfigurationBuilder() .AddInMemoryCollection(initialData) .Build(); //基于已有的配置,重新生成一个一模一样的配置。 IConfigurationRoot newConfiguration = new ConfigurationBuilder() .AddConfiguration(configuration) .Build(); Console.WriteLine("name:" + configuration["name"]); }
基于命令行的配置提供程序
基于命令行的配置程序,可以从控制台的命令行获取配置,这个配置提供程序可以快速将命令行参数分解成Key-Value键值对。而不需要我们自己手动对字符串进行处理(一般我们会按照空格拆分成数组,然后按照等号获取到键和值)
//基于命令行的配置 static void CommandLineConfig() { IConfigurationRoot configuration = new ConfigurationBuilder() .AddCommandLine(["name=tom","age=32"]) .Build(); Console.WriteLine("name:" + configuration["name"]);
基于环境变量的配置提供程序
.NET可以读取环境变量中的Key-Value键值对,并且可以过滤到指定的前缀来筛选。下面代码中,程序将会加载环境变量中以TEST_开头的所有变量到配置中,我们在系统变量中,新增一个TEST_Name的变量,一定要重启一下计算机,否则新增的环境变量不会生效。然后我们的程序就可以读取到TEST_Name的变量值
static void EnvironmentConfig() { IConfigurationRoot configuration = new ConfigurationBuilder() .AddEnvironmentVariables("Test_") .Build(); Console.WriteLine("name:" + configuration["Name"]); }
基于Json文件的配置提供程序
基于json的配置文件是我们最常用的配置文件格式了,.NET提供了标准的json配置提供程序,我们使用一下代码从一个app.json文件中加载配置,并且app.json被修改的时候,程序中的配置也会被更新。
//基于Json文件的配置 static void AddJsonFileConfig() { IConfiguration configuration = new ConfigurationBuilder() .AddJsonFile("app.json", optional: true, reloadOnChange: true) .Build(); Console.WriteLine("name:" + configuration["name"]); }
app.json的配置文件内容如下:
{ "person": { "name":"caoruipeng", "age":12, "school":"北京大学" }, "name":"tom11" }
基于XML文件的配置提供程序
基于XML的配置文件也是我们比较常用的配置文件格式了,.NET提供了标准的XML配置提供程序,我们使用一下代码从一个app.xml文件中加载配置,并且app.xml被修改的时候,程序中的配置也会被更新。
//基于XML文件的配置 static void AddXmlFileConfig() { IConfiguration configuration = new ConfigurationBuilder() .AddXmlFile("app.xml", optional: true, reloadOnChange: true) .Build(); Console.WriteLine("name:" + configuration["name"]); }
app.xml的配置文件内容如下:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <config> <name>tom</name> <age>21</age> <school>beijing</school> </config>
基于Ini文件的配置提供程序
Ini配置文件平时 我们使用的比较少,不过微软还是帮我们提供了基于Ini文件的配置提供程序。
//基于INI文件的配置 static void AddIniFileConfig() { IConfiguration configuration = new ConfigurationBuilder() .AddIniFile("app.ini", optional: true, reloadOnChange: true) .Build(); Console.WriteLine("name:" + configuration["person:name"]); }
app.ini文件的内容如下:
[person] name=tom age=27
自定义配置提供程序
官方提供的配置提供程序基本上可以满足我们的绝大部分需求,但是如果我们的配置存储在注册表中、存储在数据库中,这个时候官方的配置提供程序就无法满足我们的要求,我们就需要自定义配置提供程序。自定义配置提供程序很简单,主要包括两个类:自定义配置源IConfigurationSource
、自定义配置提供程序ConfigurationProvider
以及一个针对当前配置的扩展方法。下面代码,我们模拟一个基于数据库的配置提供程序,负责从数据库的配置表Config表中读取配置。当然案例代码,我们并不是真正的去读取数据库的表,大家可以自行完善代码。
//自定义配置源 public class DataBaseConfigurationSource : IConfigurationSource { public IConfigurationProvider Build(IConfigurationBuilder builder) { return new DataBaseConfigurationProvider(); } } //自定义配置提供程序 public class DataBaseConfigurationProvider : ConfigurationProvider { public override void Load() { base.Load(); //读取数据库配置 } } //数据库配置程序的扩展方法 public static class DataBaseConfigurationExtensions { public static IConfigurationBuilder AddDb(this IConfigurationBuilder configurationBuilder) { configurationBuilder.Sources.Add(new DataBaseConfigurationSource()); return configurationBuilder; } } //调用案例 static void Main(string[] args) { var builder = new ConfigurationBuilder() .AddDb() .Build(); var value = builder["key"]; }
以上就是.NET Core中配置Configuration的学习指南的详细内容,更多关于.NET Core配置Configuration的资料请关注脚本之家其它相关文章!