本文章介绍在 ASP.NET Core 中使用配置系统
配置提供程序可使用各种配置源从键值对读取配置数据
介绍
在 ASP.NET Core 的配置系统中有主要有三个对象
以及配置提供对象
在实际执行过程中,配置构建对象利用注册在它上面的所有配置源对象提供的配置提供对象,来读取原始配置数据,并创建出配置对象
结构化的配置
配置数据在程序中最终以 IConfiguration 的形式体现,数据来源可能是内存对象、物理文件、数据库等等,这个对象体现为一个树形逻辑结构,将每一个配置项的路径作为 Key,那么每一个配置项都是一个 Key-Value 的形式,在系统中子节点与父节点的分隔符用 : 来表示
以下是一段使用内存配置源来建构配置对象
var source = new Dictionary<string, string>
{
["A:B:C"] = "ABC",
["A:B:D"] = "ABD",
};
IConfigurationRoot root = new ConfigurationBuilder()
.AddInMemoryCollection(source)
.Build();
IConfigurationSection section1 = root.GetSection("A:B:C");
IConfigurationSection section2 = root.GetSection("A:B").GetSection("C");
IConfigurationSection section3 = root.GetSection("A").GetSection("B:C");
string section1Value = root["A:B:C"]; // ABC
string section2Value = root.GetSection("A:B")["C"]; // ABC
Debug.Assert(section1.Value == "ABC");
Debug.Assert(section2.Value == "ABC");
Debug.Assert(section3.Value == "ABC");
复制代码
在以上代码中,使用 A:B:C,A:B:D 建构了一个 Y 形的树状数据结构,
可以直接使用 GetSection("A:B:C") 直接拿到最终的子节点,也可以先拿到子节点 GetSection("A:B") 然后从拿到的子节点去寻找最终的子节点 GetSection("C") ,
最后我们通过三个不同路径拿到的 Value 来判断是否都等于 ABC。
不同的配置源
首先需要使用不同源的 Nuget 包
> # 输入命令从 NuGet 安装, 我用的NuGet版本为 Scrutor 3.1.3
> dotnet add package Microsoft.Extensions.Configuration.Xml
> dotnet add package Microsoft.Extensions.Configuration.Json
> dotnet add package Microsoft.Extensions.Configuration.CommandLine
> dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables
> dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions
复制代码
基于内存的配置
基于内存的配置需要往配置构建对象上面注册内存配置源对象
其中 AddInMemoryCollection(source) 和 Add(new MemoryConfigurationSource { InitialData = source }) 是一样的效果
我们用之前定义的 Log 类,用来承载内存配置
var source = new Dictionary<string, string>
{
["Display"] = "true",
["LogLevel:Default"] = "Information",
["LogLevel:Microsoft"] = "Warning"
};
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(source)
// .Add(new MemoryConfigurationSource { InitialData = source })
.Build();
var log = configuration.Get<Log>();
复制代码
执行代码可以发现,基于内存的值已经绑定在了 log 对象中
基于 Json 文件的配置
这里准备了一个 appsettings.json 文件
{
"Display": true,
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning"
}
}
复制代码
注册 Json 文件配置源对象时
AddJsonFile("appsettings.json") 和 Add(new JsonConfigurationSource { Path = "appsettings.json" }) 是一样的效果
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
// .Add(new JsonConfigurationSource { Path = "appsettings.json" })
.Build();
var log = configuration.Get<Log>();
复制代码
执行代码可以发现,基于 Json 文件的配置已经绑定在了 log 对象中
基于 Xml 文件的配置
这里准备了一个 appsettings.config 文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<Display>True</Display>
<LogLevel>
<Default>Warning</Default>
<Microsoft>Warning</Microsoft>
</LogLevel>
</configuration>
复制代码
注册 Json 文件配置源对象时
AddXmlFile("appsettings.config") 和 Add(new XmlConfigurationSource { Path = "appsettings.config" }) 是一样的效果
var configuration = new ConfigurationBuilder()
.AddXmlFile("appsettings.config")
// .Add(new XmlConfigurationSource { Path = "appsettings.config" })
.Build();
var log = configuration.Get<Log>();
复制代码
执行代码可以发现,基于 Xml 文件的配置已经绑定在了 log 对象中
基于环境变量的配置
在使用环境变量配置时,AddEnvironmentVariables 方法还有一个重载是传一个字符串,该字符串作为环境变量的前缀,注册的环境变量名必须以其开头的前缀。而前缀将从环境变量名中删除
Environment.SetEnvironmentVariable("App_Display", "true");
Environment.SetEnvironmentVariable("LogLevel:Default", "Warning");
Environment.SetEnvironmentVariable("LogLevel:Microsoft", "Warning");
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddEnvironmentVariables("App_")
.Build();
var java_home = configuration["JAVA_HOME"]; // D:\Other\java\jdk-14.0.2
var log = configuration.Get<Log>();
复制代码
执行代码可以看到 java_home 拿到了 JAVA JDK 的环境变量
还拿到了并将内存中设置的环境变量绑定到了 log 对象中
基于命令行映射的配置
static void Main(string[] args)
{
// -d 是配置的简写映射, Display 是配置项名称(--Display /Display)
var mapping = new Dictionary<string, string>()
{
["-d"] = "Display",
["-ld"] = "LogLevel:Default",
["-lm"] = "LogLevel:Microsoft",
};
var configuration = new ConfigurationBuilder()
.AddCommandLine(args, mapping)
.Build();
var log = configuration.Get<Log>();
Console.WriteLine(log?.Display);
Console.WriteLine(log?.LogLevel?.Default);
Console.WriteLine(log?.LogLevel?.Microsoft);
}
复制代码
编译成 dll 文件以后通过命令行执行,以下三句指令效果相同
> dotnet .\File.ConsoleApp2.dll -d True -ld Warning -lm Warning
> dotnet .\File.ConsoleApp2.dll --Display True --LogLevel:Default Warning --LogLevel:Microsoft Warning
> dotnet .\File.ConsoleApp2.dll --Display True /LogLevel:Default Warning /LogLevel:Microsoft Warning
复制代码
不加参数直接执行得到的结果将是 三行空白,通过上面某一句指令执行的结果是我们输入的值,说明我们输入的参数被成功绑定到了 log 对象上
其他
如果同时在配置构建对象中注册多个配置源对象
var configuration = new ConfigurationBuilder()
.AddXmlFile("appsettings.config")
.AddJsonFile("appsettings.json")
.Build();
复制代码
那么得到的结果将是后面的相同的配置将会覆盖前面的配置
监控文件的变化
在将文件配置源对象注册到配置构建对象时,会有重载传参,其中有可选择文件是否可以不存在,还有是否监听文件的变化
比如这里的 AddJsonFile("appsettings.json", true, true) 第二个参数是文件可以不存在,第三个参数为要监听文件的变化
static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", true, true)
.Build();
Read(config.Get<Log>());
ChangeToken.OnChange(() => config.GetReloadToken(), () =>
{
Read(config.Get<Log>());
});
Console.Read();
}
public static void Read(Log options)
{
Console.Clear();
Console.WriteLine($"Display=>{options.Display}");
Console.WriteLine($"LogLevel:Default=>{options.LogLevel.Default}");
Console.WriteLine($"LogLevel:Microsoft=>{options.LogLevel.Microsoft}");
}
复制代码
在修改 appsettings.json 文件时
每次修改都能触发 ChangeToken.OnChange 的第二个参数,即回调
评论