文章目录
- 1.配置框架
- 1.1 核心包
- 1.2 配置框架核心类型
- 1.3 配置框架扩展点
- 2.命令行配置提供程序
- 2.1 支持的命令格式
- 2.2 命令替换模式
- 3. 环境变量配置提供程序
- 3.1 使用场景
- 3.2 特性
- 4.文件配置提供程序
- 4.1 文件配置提供程序
- 4.2 特性
- 5.配置变更监听-配置热更新能力的核心
- 5.1 场景
- 5.2 关键方法
- 6.配置绑定-使用强类型对象承载配置数据
- 6.1 要点
- 7.自定义配置数据源-低成本实现定制化配置方法
- 7.1 扩展步骤
1.配置框架
1.1 核心包
- Microsoft.Extensions.Configuration.Abstractions
- Microsoft.Extensions.Configuration
以Key-value键值对方式抽象配置,支持从不同数据源读取配置,如环境变量,数据库等
1.2 配置框架核心类型
- IConfiguration
- IConfigurationRoot
- IConfigurationSection
- IConfigurationBuilder
1.3 配置框架扩展点
- IConfigurationSource
- IConfigurationProvider
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(new Dictionary<string,string>()// 注入内存的配置数据源
{
{"key1","value1"},
{"key2","value2"},
{"section1:key4","value4"} ,// section用于配置分组
{"section2:key5","value5"} ,
{"section2:key6","value6"} ,
{"section2:section3:key7","value7"} ,// 多层嵌套
});
IConfigurationRoot configurationRoot = builder.Build();// 构建所有配置
Console.WriteLine(configurationRoot["key1"]);// 读取配置
Console.WriteLine(configurationRoot["key2"]);
// 获取section
IConfigurationSection section = configurationRoot.GetSection("sction1");
Console.Writeline(section["key4"]); // 输出结果为 value4
Console.WriteLine(section["key5"]); // 无法获取值
IConfigurationSection section2 = configurationRoot.GetSection("sction2");
Console.WriteLine(section["key5"]); // 输出结果为value5
var section3 = section2.GetSection("section3");// 多层嵌套的读取
Console.WriteLine(section3["key7"]);// 输出结果为value7
}
2.命令行配置提供程序
2.1 支持的命令格式
- 无前缀的key=value 模式
- 双中横线模式 --key=value 或 – key value
- 正斜杠模式 /key=value 或 /key value
备注 : 等号分隔符和空格分隔符不能混用
2.2 命令替换模式
就是可以给命令取别名
- 必须以单划线(-)或双划线(–)开头
- 映射字典不能包含重复key
// 控制台应用程序
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddCommandLine(args);
// 命令替换
//var mapper = new Dictionary<string,string>{{"-k1","CommandLineKey1"}};// 把-k1的值换给CommandLineKey1
//builder.AddCommandLine(args,mapper);
var configurationRoot = builder.Builder();
Console.WriteLine($"CommandLineKey1:{configurationRoot["CommandLineKey1"]}");
Console.ReadKey();
}
在项目属性-调试-应用程序参数中设置启动参数 ,设置四个参数
CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3 -k1=k3
3. 环境变量配置提供程序
3.1 使用场景
- 在Docker中运行时
- 在Kubernetes中运行时
- 需要配置Asp.NetCore的一些内置特殊配置时
3.2 特性
- 对于配置的分层键,支持用双下横线"__“代替”:"
- 支持根据前缀加载
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddEnvironmentVariables();
var configurationRoot = builder.Builder();
Console.WriteLine($"key1:{configurationRoot["CommandLineKey1"]}");
// 分层键
var section = configurationRoot.GetSection("SECTION1");
Console.WriteLine($"KEY3:{section["KEY3"]}"); // 输出为 : value3
// 前缀过滤
builder.AddEnvironmentVariables("XIAO_");
var configurationRoot = builder.Builder();
Console.WriteLine($"key1:{configurationRoot["KEY1"]}");
}
环境变量配置:
项目右键-属性-调试,设置环境变量
4.文件配置提供程序
4.1 文件配置提供程序
- Micosoft.Extensions.Configuration.Ini
- Micosoft.Extensions.Configuration.Json
- Microsoft.Extensions.Configuration.NewtonsoftJson
- Microsoft.Extensions.Configuration.Xml
- Microsoft.Extensions.Configuration.UserSecrets
4.2 特性
- 指定文件可选、必选
- 指定是否监视文件的变更
// 控制台程序
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
// optional表示文件是否可选,默认为false,表示文件不存在时会报错
// reloadChange表示文件变更是否重新读取,默认为true
builder.AddJsonFile("appsettings.json",optional:false,reloadOnChange:true);
builder.AddIniFile("appsetting.ini");// 这个配置会覆盖前面的配置信息,优先级更高
var configurationRoot = builder.Builder();
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");// 输出结果 value1
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");// 输出结果value2
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");// 输出为空
Console.ReadKey();
}
引用程序包
appsettings.json配置
5.配置变更监听-配置热更新能力的核心
5.1 场景
- 需要记录配置源的变更时
- 需要在配置数据变更时触发特定操作时
5.2 关键方法
- IChangeTokenIconfiguration.GetReloadToken()
// 控制台程序
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true);
var configurationRoot = builder.Builder();
IChangeToken token = configurationRoot.GetReloadToken();//IChangeToken只能使用一次
ChangeToken
token.RegisterChageCallback(state => { // 修改配置文件时读取
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
},configurationRoot);
Console.ReadKey();
//Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
//Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
//Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
//Console.ReadKey();
}
appsettings.json配置
注意:这里只能监听到一次配置文件的修改,修改一次后再次修改,将无法捕获到修改信息
因为IChangeToken对象只能使用一次,如果需要持续监听,需要在结束后重新获取一次IChangeToken,如下代码所示
// 改进后代码
// 控制台程序
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true);
var configurationRoot = builder.Builder();
IChangeToken token = configurationRoot.GetReloadToken();//IChangeToken只能使用一次
// 持续监听修改
ChangeToken.OnChange(() => configurationRoot.GetReloadToken(),()=>
{
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
});
Console.ReadKey();
}
6.配置绑定-使用强类型对象承载配置数据
6.1 要点
- 支持将配置值绑定到已有对象
- 支持将配置值绑定到私有属性上(默认情况只能绑定public属性)
// 控制台程序
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true);
var configurationRoot = builder.Builder();
var config = new Config();
config.Key1 = "config key1";
config.Key5 = true;
config.Key6 = 100;
configurationRoot.Bind(config);
//configurationRoot.GetSection("section名称").Bind(config);//多层级绑定
Console.WriteLine($"Key1:{config.Key1}");// 输出Key1:Value1
Console.WriteLine($"Key5:{config.Key5}");// 输出Key5:false
Console.WriteLine($"Key6:{config.Key6}");// 输出Key6:10
}
class Config
{
public string Key1 { get; set;}
public bool Key5 { get; set;}
public int Key6 { get; set;}
}
appsettings.json配置
通常会遇到多层级的配置,采用如下方式
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true);
var configurationRoot = builder.Builder();
var config = new Config();
config.Key1 = "config key1";
config.Key5 = true;
config.Key6 = 100;
configurationRoot.GetSection("OrderService").Bind(config,binderOptions => {
binderOptions.BindNonPublicProperties = true; //BindNonPublicProperties 私有属性是否绑定.默认false
});//多层级绑定
Console.WriteLine($"Key1:{config.Key1}");// 输出Key1:order key1
Console.WriteLine($"Key5:{config.Key5}");// 输出Key5:true
Console.WriteLine($"Key6:{config.Key6}");// 输出Key6:200
// 读取到的是appsettings.json中内容
}
对应的appsettings.json如下
一般推荐使用强类型进行绑定,Bind方法在开发中使用会比较多
7.自定义配置数据源-低成本实现定制化配置方法
7.1 扩展步骤
- 实现IConfigurationSource
- 实现IConfigurationProvider
- 实现Addxxx扩展方法
IConfigurationSource
class MyConfigurationSource : IConfigurationSouce
{
public IConfigurationProvider Builde(IConfigurationBuilder builder)
{
return new MyConfigurationProvider();
}
}
using System.Timers.Timer;
public class MyConfigurationProvider : ConfigurationProvider
{
Timer timer;
public MyConfigurationProvider() : base()
{
timer = new Timer();
timer.Elapsed += Timer_Elasped;
timer.Interval = 3000;
timer.Start();
}
private void Timer_Elasped(object? sender, ElapsedEventArgs e)
{
Load(true);
}
public override void Load()
{
// 加载数据
Load(false);
}
void Load(bool reload)
{
this.Data["lastTime"] = DateTime.Now.ToString();
if (reload)
{
base.OnReload();
}
}
}
// 定义扩展方法,暴露在外的扩展方法,不需要将具体的配置源实现向外暴露
namespace Microsoft.Extensions.Configuration // 使用Configuration命名空间
{
public static class MyConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder)
{
builder.Add(new MyConfigurationSource());
return builder;
}
}
}
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
//builder.Add(new MyConfigurationSource());// 直接读取具体配置
builder.AddMyConfiguration();/ 通过扩展方法获取
var configRoot = builder.Build();
// 持续监听
ChangeToken.OnChange(() => configRoot.GetReloadToken(), () =>
{
var value = configRoot["lastTime"];
Console.WriteLine(value);
});
Console.WriteLine("开始了");
Console.ReadKey();
}
定义扩展时,将具体的实现定义为私有的internal,然后通过扩展方法的方式暴露出去
输出结果