0%

NetCore框架的配置

配置框架的核心组件包及核心类型

  • 核心组件包:

    1. Microsoft.Extensions.Configuration.Abstractions
    2. Microsoft.Extensions.Configuration
  • 核心类型

    1. IConfiguration
    2. IConfigurationRoot
    3. IConfigurationSection
    4. IConfigurationBuilder
  • 配置框架的扩展点

    1. IConfigurationSource
    2. IConfigurationProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//用来构建数据源
IConfigurationBuilder builder = new ConfigurationBuilder();
//定义了一个内存的数据配置源
builder.AddInMemoryCollection(new Dictionary<string, string>
{
{"key1", "value1" },
{"key2", "value2" },
{"section1:key3", "value3" },
{"section2:section3:key4", "value4" }
});
//构建数据源
IConfigurationRoot configurationRoot = builder.Build();
//读取配置信息
Console.WriteLine($"key1:{configurationRoot["key1"]}");
Console.WriteLine($"key2:{configurationRoot["key2"]}");
//定义一个节点,用来读取value3
IConfigurationSection section1 = configurationRoot.GetSection("section1");
Console.WriteLine($"section1:key3:{section1["key3"]}");
//嵌套节点
IConfigurationSection section2 = configurationRoot.GetSection("section2");
var section3 = section2.GetSection("section3");
Console.WriteLine($"section2:section3:key4:{section3["key4"]}");

命令行配置提供程序

  • 支持的命令格式:

    1. 无前缀的 key=value模式
    2. 双中横线模式 –key=value或 –key value
    3. 正斜杠模式 /key=value或/key value

    注意:等号连字符和空格连字符不能混用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var builder = new ConfigurationBuilder();
//builder.AddCommandLine(args);

#region 命令替换
//将CommandLineKey2的value替换为-k2的value
var mapper = new Dictionary<string, string> {{"-k2", "CommandLineKey2"}};
builder.AddCommandLine(args, mapper);

#endregion

var configurationRoot = builder.Build();
Console.WriteLine($"CommandLineKey1:{configurationRoot["CommandLineKey1"]}");
Console.WriteLine($"CommandLineKey2:{configurationRoot["CommandLineKey2"]}");
Console.WriteLine($"CommandLineKey3:{configurationRoot["CommandLineKey3"]}");

Console.ReadKey();

环境变量配置提供程序

  • 该配置方式一般在Docker或K8s中使用,当AspNetCore需要一些内置的配置时也可使用
  • 配置的分层键,”__”代替”:”,还支持根据前缀加载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var builder = new ConfigurationBuilder();
builder.AddEnvironmentVariables();

var configurationRoot = builder.Build();
Console.WriteLine($"key1:{configurationRoot["EnvironmentKey1"]}");

#region 分层键

var section1 = configurationRoot.GetSection("Section1");
Console.WriteLine($"key3:{section1["Key3"]}");
var section2 = configurationRoot.GetSection("Section1:Section2");
Console.WriteLine($"key4:{section2["Key4"]}");

#endregion

#region 前缀过滤

builder.AddEnvironmentVariables("Fre_");
var configurationRoot2 = builder.Build();
Console.WriteLine($"key5:{configurationRoot2["key5"]}");
Console.WriteLine($"key6:{configurationRoot2["key6"]}");

#endregion

文件配置提供程序

  • 配置文件的类型有:ini,json,newtonsoftjson,xml,usersecrets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var builder = new ConfigurationBuilder();
string dir = Path.GetFullPath("../../..");
//optional参数为false时,当文件不存在时会报错,否则不会报错
//reloadOnChange参数为true时,表示在程序运行的过程中,修改文件会重新加载文件,否则不加载
builder.AddJsonFile($"{dir}/appsettings.json", false, true);

var configurationRoot = builder.Build();
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
Console.WriteLine($"Key4:{configurationRoot["Key4"]}");
Console.ReadKey();
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
Console.WriteLine($"Key4:{configurationRoot["Key4"]}");
Console.ReadKey();
//读取ini文件中的配置,后添加的配置文件会覆盖前面的配置文件,即ini文件会覆盖json文件
builder.AddIniFile($"{dir}/appsettings.ini", false, true);
var configurationRoot2 = builder.Build();
Console.WriteLine($"Key1:{configurationRoot2["Key1"]}");

配置变更监听

  • 场景:1、需要记录配置源的变更时,2、需要在配置数据变更时触发特定操作时
  • GetReloadToken()、RegisterChangeCallback
1
2
3
4
5
6
7
8
9
10
11
12
13
var configurationRoot = builder.Build();
//获取reloadtoken
IChangeToken token = configurationRoot.GetReloadToken();
RegisterChangeCallback会监视configurationRoot中配置信息的变化,
//当配置信息变化时,该方法就会执行callback方法,但RegisterChangeCallback
//只会监听一次
token.RegisterChangeCallback(state =>
{
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
Console.WriteLine($"Key4:{configurationRoot["Key4"]}");
}, configurationRoot);
  • OnChange静态方法
1
2
3
4
5
6
7
8
9
10
11
/*
*OnChange方法的功能和RegisterChangeCallback一样,但它能监听多次变化
*第一个参数为配置更新后如何获取reloadtoken,第二个参数是配置更新后执行的操作
*/
ChangeToken.OnChange(() => configurationRoot.GetReloadToken(), () =>
{
Console.WriteLine($"Key1:{configurationRoot["Key1"]}");
Console.WriteLine($"Key2:{configurationRoot["Key2"]}");
Console.WriteLine($"Key3:{configurationRoot["Key3"]}");
Console.WriteLine($"Key4:{configurationRoot["Key4"]}");
});

配置绑定

  • 将配置值绑定到已有对象,使用Bind方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Program
{
static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
var dir = Path.GetFullPath("../../..");
builder.AddJsonFile($"{dir}/appsettings.json", false);

var configurationRoot = builder.Build();
var config = new OrderConfig
{
Key1 = "config key1",
Key2 = "config key2",
Key3 = true
};
/*使用bind方法可以把配置文件中的数据绑定到代码中具体的类中*/

configurationRoot.GetSection("OrderConfig").Bind(config);
Console.WriteLine($"Key1:{config.Key1}");
Console.WriteLine($"Key2:{config.Key2}");
Console.WriteLine($"Key3:{config.Key3}");
Console.WriteLine($"Key4:{config.Key4}");
}
}

class OrderConfig
{
public string Key1 { get; set; }
public string Key2 { get; set; }
public bool Key3 { get; set; }
public int Key4 { get; set; }

}
  • 将配置值绑定到私有属性上,在bind方法中传入一个设置委托,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* 若是set为私有的属性,可以在bind方法中把BindNonPublicProperties设置为true
* bind方法对没有set的属性是不生效的
*/
configurationRoot.GetSection("OrderConfig").Bind(config, opt =>
{
opt.BindNonPublicProperties = true;
});
class OrderConfig
{
public string Key1 { get; set; }
public string Key2 { get; set; }
public bool Key3 { get; set; }
//把set设置为private
public int Key4 { get; private set; } = 100;

}

自定义配置数据源

  • 定义配置的提供者MyConfigurationProvider,该自定义类既可以实现IConfigurationProvider接口,又可继承ConfigurationProvider这个抽象类,在这里我们选择继承ConfigurationProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MyConfigurationProvider : ConfigurationProvider
{
private Timer timer;

public MyConfigurationProvider()
{
//每隔3秒重新加载一下数据
timer = new Timer();
timer.Elapsed += Time_Elapsed;
timer.Interval = 3000;
timer.Start();
}
public override void Load()
{
//框架初次加载数据
Load(false);
}

private void Time_Elapsed(object sender, ElapsedEventArgs e)
{
//重新加载数据
Load(true);
}

void Load(bool reload)
{
//Data是ConfigurationProvider类提供的一个存储数据的集合,可用来存储配置信息
//将最新时间填充到数据集合中
Data["lastTime"] = DateTime.Now.ToString();
if (reload)
{
OnReload();
}C#
}
}
  • 定义配置的数据源MyConfigurationSource,该类实现了IConfigurationSource接口,并返回一个MyConfigurationProvider的实例
1
2
3
4
5
6
7
public class MyConfigurationSource:IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new MyConfigurationProvider();
}
}
  • 定义一个扩展方法,作为程序使用数据源的接口,这样做的目的是不会向外部暴露我们定义的数据源类
1
2
3
4
5
6
7
8
public static class MyConfigurationBuilderExtension
{
public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder)
{
builder.Add(new MyConfigurationSource());
return builder;
}
}
  • 使用自定义数据源
1
2
3
4
5
6
7
8
9
10
var builder = new ConfigurationBuilder();
builder.AddMyConfiguration();
var configurationRoot = builder.Build();
//该程序会每三秒打印一次最新的时间
ChangeToken.OnChange(() => configurationRoot.GetReloadToken(), () =>
{
var lastTime = configurationRoot["lastTime"];
Console.WriteLine($"lastTime:{lastTime}");
});
Console.ReadKey();
-------------本文结束感谢您的阅读-------------