ASP.NET Core框架学习之配置框架
配置是应用程序发布到各种环境的必备能力。.net core框架本身集成了强大的配置功能,支持多种配置源数据读写。
经常使用的nuget包
Microsoft.Extensions.Configuration.Abstractions //抽象包
Microsoft.Extensions.Configuration //实现包
Microsoft.Extensions.Configuration.Binder //强类型绑定
Microsoft.Extensions.Configuration.Json //配置Json文件
Microsoft.Extensions.Primitives //配置验证
Microsoft.Extensions.Options //配置选项
框架核心接口
IConfigurationBuilder //建造者接口 IConfigurationRoot //配置根 IConfigurationSource //配置源接口 IConfigurationProvider //配置提供程序接口
配置框架应用了建造者模式,我们需要将配置源提交给建造者,通过建造者接口提供的build方法,创建IConfigurationRoot实例,它是配置的根,我们可以通过IConfigurationRoot实例访问到配置文件。通过实现IConfigurationSource ,IConfigurationProvider 两个接口,我们也可以在框架中添加自定义的配置源。
Web Api项目的简单实例
在appsettings.json中设置配置文件
{ "key1": "nihao", "section1": { "key1": [ "1", "2" ], "key2":4 } }
构造函数中添加IConfiguration接口,并使用_configuration读取配置
private readonly IConfiguration _configuration; public WeatherForecastController(IConfiguration configuration) { _configuration = configuration; } [HttpGet] public string Get() { Console.WriteLine(_configuration["key1"]); //读取配置 Console.WriteLine(_configuration.GetSection("section1")["key2"]); return "OK"; }
因为ASP.NET Core框架已经默认添加了appsettings.json的配置源,所以我们直接使用IConfiguration接口就可以读取到其中的配置,如果我们需要添加新的配置文件则需要手动添加(注意:后添加的配置源,会覆盖掉与前面配置源相同key的value值。)
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(builder => { builder.AddJsonFile("dbsettings.json", false, true); //添加新的配置源 optional:是否可选,为false时,启动时未找到该配置文件会程序异常。 reloadOnChange:配置变更时,是否重新加载配置。 }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
控制台程序实例
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddJsonFile("appsettings.json", false, true); var iconfigurationRoot = configurationBuilder.Build(); Console.WriteLine($"key1 {iconfigurationRoot["key1"]}");
强类型绑定
配置框架支持将配置文件与类型绑定,它可以让我们使用配置更加方便,也使配置结构更加清晰。
创建一个SectionOptions类型
public class SectionOptions { public string[] key1 { get; set; } public int key2 { get; set; } = 2; }
在ConfigureServices方法中添加如下代码
var config = new SectionOptions() { }; Configuration.GetSection("section1").Bind(config, options => //将配置文件中的section1分段与config实例绑定 { options.BindNonPublicProperties = true; //支持私有属性绑定 }); services.AddSingleton<SectionOptions>(config);
这样我们就可以在构造函数中引入SectionOptions,并通过它来读写配置文件了。
配置变更监听
给配置文件变更事件设置回调函数,当配置文件更新时,我们可以在回调函数中,做相应的逻辑处理
ChangeToken.OnChange(() => { return Configuration.GetReloadToken(); }, () => { Console.WriteLine(Configuration["key1"]); });
配置选项
配置选项模式让类型绑定变得更加简单、灵活。它支持三种模式:IOptions,IOptionsMonitor,IOptionsSnapshot。
在ConfigureServices中添加如下代码
services.Configure<SectionOptions>(Configuration.GetSection("section1"));
在构造函数中通过IOptions模式使用SectionOptions,它不能动态重载配置的变更
private readonly SectionOptions _sectionOptions; public WeatherForecastController(IOptions<SectionOptions> options) { _sectionOptions = options.Value; }
在构造函数中通过IOptionsMonitor模式使用SectionOptions,它支持动态重载配置的变更,并保证每次读取的配置值都是最新的
private readonly SectionOptions _sectionOptions; public WeatherForecastController(IOptionsMonitor<SectionOptions> options) { _sectionOptions = options.CurrentValue; }
在构造函数中通过IOptionsSnapshot模式使用SectionOptions,它支持动态重载配置的变更,但同一次请求域内,多次请求的值保持一致(可用来防止单次请求内由于配置文件变更引起的数据处理问题)
private readonly SectionOptions _sectionOptions; public WeatherForecastController(IOptionsSnapshot<SectionOptions> options) { _sectionOptions = options.Value; }
配置验证
配置框架还提供了三种配置验证的机制,当配置错误时,使用该配置程序会抛出异常。
DataAnnotations特性验证,在模型中使用DataAnnotations特性标记
services.AddOptions<SectionOptions>().Configure(option => { Configuration.GetSection("section1").Bind(option); }).ValidateDataAnnotations();
函数验证,在绑定配置时,直接注入验证函数
services.AddOptions<SectionOptions>().Configure(option => { Configuration.GetSection("section1").Bind(option); }).Validate(section => { return section.key2 > 1; });
实现IValidateOptions接口
public class SectionValidateOptions : IValidateOptions<SectionOptions> { public ValidateOptionsResult Validate(string name, SectionOptions options) { if (options.key2 > 100) { return ValidateOptionsResult.Fail("key2 不能大于100"); } else { return ValidateOptionsResult.Success; } } } //在ConfigureServices方法中添加如下代码 services.AddOptions<SectionOptions>().Configure(option => { Configuration.GetSection("section1").Bind(option); }).Services.AddSingleton<IValidateOptions<SectionOptions>, SectionValidateOptions>();
后配置处理
配置框架还提供了方法让我们对配置数据进行处理
services.PostConfigure<SectionOptions>(options => { options.key2 += 10; });
自定义配置源
通过实现下面的两个接口,我们可以实现自己的配置提供程序,它可以用来获取远程配置中心的配置。
public class MyConfigurationSource : IConfigurationSource { public IConfigurationProvider Build(IConfigurationBuilder builder) { return new MyConfigurationProvider(); } } public class MyConfigurationProvider : ConfigurationProvider, IConfigurationProvider { public MyConfigurationProvider() { var timer = new Timer(); timer.Elapsed += Timer_Elapsed; timer.Interval = 3000; timer.Start(); } private void Timer_Elapsed(object sender, ElapsedEventArgs e) { Load(true); } public void Load() { Load(false); } private void Load(bool reload = false) { //可以在这里加载远程配置中心的配置 this.Data["lastdatetime"] = $"{DateTime.Now}"; if (reload) { base.OnReload(); } } }
添加自定义配置源
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(builder => { // builder.Add(new MyConfigurationSource()); //添加自定义配置源 }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
这样我们就可以通过配置框架获取到自定义配置源中的数据了。