用法
- 推荐使用选项方式读取,和DI结合更好,而且更好利用"raloadonchange"机制。
- NuGet安装:
Microsoft.Extensions.Options & Microsoft.Extensions.Configuration.Binder & Microsoft.Extensions.Configuration & Microsoft.Extensions.Configuration.Json - 读取配置的时候,DI要声明IOptions<T> 、 IOptionsMonitor<T>、IOptionsSnapshot<T>等类型。 IOptions<T>不会读取到新的值;和IOptionsMonitor<T>相比,IOptionsSnapshot<T>会在同一个范围内保持一致。建议使用IOptionsSnapshot。
2 演示代码
TestController类
using System;
using Microsoft.Extensions.Options;
namespace 配置系统学习_2
{
class TestController
{
// di注入的对象一般都写成readonly的
private readonly IOptionsSnapshot<Config> optionsSnapshot;
// private readonly Config config;
public TestController(IOptionsSnapshot<Config> optionsSnapshot)
{
//不要写成下面这种形式,这样写是在注入时就取到配置文件中的值
//但是以后更改配置文件的话会取不到更新的值
//this.config = optionsSnapshot.Value;
// 要拿到optionsSnapshot,它会在配置文件作修改时帮我们取到新的值
this.optionsSnapshot = optionsSnapshot;
}
public void Test()
{
Console.WriteLine(optionsSnapshot.Value.Age);
Console.WriteLine("********");
Console.WriteLine(optionsSnapshot.Value.Age);
}
}
}
Program类
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace 配置系统学习_2;
class Program
{
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<TestController>();
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("Config.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
services.AddOptions().Configure<Config>(e => configRoot.Bind(e));
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestController controller = sp.GetRequiredService<TestController>();
controller.Test();
}
}
}
class Proxy
{
public string Address { get; set; }
public int Port { get; set; }
}
class Config
{
public string Name { get; set; }
public int Age { get; set; }
public Proxy Proxy { get; set; }
}
congfig.json 配置文件
{
"name": "mzz",
"age": 58,
"proxy": {
"address": "ttt",
"port": 1844
}
}
如果我们只想读proxy的配置内容,不想将整个config读出来,怎么办?
新增一个TestController2
using System;
using Microsoft.Extensions.Options;
namespace 配置系统学习_2
{
class TestController2
{
private readonly IOptionsSnapshot<Proxy> optionSnapshot;
public TestController2(IOptionsSnapshot<Proxy> optionSnapshot)
{
this.optionSnapshot = optionSnapshot;
}
public void Test2()
{
Console.WriteLine(this.optionSnapshot.Value.Address);
}
}
}
Program 类
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace 配置系统学习_2;
class Program
{
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<TestController2>();
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("Config.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
// 这句最重要 是将配置文件的对应类绑定到root上,可以绑定多个配置配件
services.AddOptions()
.Configure<Proxy>(e => configRoot.GetSection("proxy").Bind(e));
using (ServiceProvider sp = services.BuildServiceProvider())
{
var controller2 = sp.GetRequiredService<TestController2>();
controller2.Test2();
}
}
}
class Proxy
{
public string Address { get; set; }
public int Port { get; set; }
}
class Config
{
public string Name { get; set; }
public int Age { get; set; }
public Proxy Proxy { get; set; }
}
到这里,我们还没有看出来snapshot在一定范围内加载同一个值是什么意思,我们现在将program类中的代码改变一下:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace 配置系统学习_2;
class Program
{
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<TestController>();
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("Config.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
// 这句最重要 是将配置文件的对应类绑定到root上,可以绑定多个配置配件
services.AddOptions()
.Configure<Config>(e => configRoot.Bind(e));
using (ServiceProvider sp = services.BuildServiceProvider())
{
while (true)
{
using (IServiceScope scope = sp.CreateScope())
{
var controller = scope.ServiceProvider.GetRequiredService<TestController>();
controller.Test(); // 配置文件中age=58
Console.WriteLine("please change the age:");//改为38
Console.ReadKey();
controller.Test();
}
Console.WriteLine("please press any key to continue");
Console.ReadKey();
}
}
}
}
class Proxy
{
public string Address { get; set; }
public int Port { get; set; }
}
class Config
{
public string Name { get; set; }
public int Age { get; set; }
public Proxy Proxy { get; set; }
}
最能体现snapshot在一定范围内加载同一个值的是下面这段代码。我们写一个循环,在这个循环里面创建了一个scope,在这个scope里面分别打印了两次config中的age,一次在修改age前,一次在修改age后,由运行结果可知,这两次的结果是一致的。之后进入下一个循环打印出来的是修改过后的age值。
这里有个点需要注意:修改config文件时,修改的不是和项目同级的json文件,而是和exe同一个目录下面的json文件。具体可参照上篇文章。
while (true)
{
using (IServiceScope scope = sp.CreateScope())
{
var controller = scope.ServiceProvider.GetRequiredService<TestController>();
controller.Test(); // 配置文件中age=58
Console.WriteLine("please change the age:");//改为38
Console.ReadKey();
controller.Test();
}
Console.WriteLine("please press any key to continue");
Console.ReadKey();
}