在ASP.NET Core笔记(3) - 配置中介绍了各类配置提供程序以及配置的读取方式,但实际使用中,不推荐应用程序直接从一堆配置中读取的作法,而是使用强类型绑定,将配置按组绑定到不一样服务所属的类。使用这种方式可让配置方案遵照两个重要的软件工程原则:ide
ASP.NET Core选项模式经常使用的接口有函数
IOptions在配置更改时没法对应变动选项的值,只能重启应用。IOptionsSnapshot和IOptionsMonitor则具备这种能力。code
选项能够做为服务在使用时被注入,下面的代码模拟了选项的使用场景,OrderServiceOptions做为OrderService的选项被注入,OrderService又在控制器中被注入:对象
public interface IOrderService { int ShowMaxOrderCount(); } public class OrderService : IOrderService { IOptionsSnapshot<OrderServiceOptions> _options; public OrderService(IOptionsSnapshot<OrderServiceOptions> options) { _options = options; } public int ShowMaxOrderCount() { return _options.Value.MaxOrderCount; } } public class OrderServiceOptions { public int MaxOrderCount { get; set; }; }
控制器中注入OrderService:接口
[HttpGet] public string Get([FromServices]IOrderService orderService) { var res = $"orderService.ShowMaxOrderCount:{orderService.ShowMaxOrderCount()},time={orderService.ShowTime()}"; Console.WriteLine(res); return res; }
在ConfigService配置OrderServiceOptions和OrderService的注入:生命周期
services.Configure<OrderServiceOptions>(Configuration.GetSection("OrderService")); services.AddScoped<IOrderService, OrderService>();
这里注入时使用的是AddScoped做用域的方式,是由于使用了IOptionsSnapshot接口。IOptionsSnapshot的生命周期为做用域,会在每次请求时应从新读取配置、更新选项。因此修改配置后,从新请求API,就能够看到最新的配置值。
若是尝试选择AddSingleton,因为OrderService单例的生命周期比IOptionsSnapshot更长,会直接抛出运行时异常。事件
而若是遇到既须要单例生命周期,还须要变动检测的场景时怎么办呢?这时就须要用到IOptionsMonitor了。
IOptionsMonitor 和 IOptionsSnapshot 之间的区别在于:作用域
IOptionsMonitor使用与IOptionsSnapshot相似,但取值变为CurrentValue。若是修改配置源,就会触发OnChange方法:get
_options.OnChange(option => { Console.WriteLine($"配置更新了,最新的值是:{_options.CurrentValue.MaxOrderCount}"); });
IOptionsMonitor还能够结合ASP.NET Core笔记(3) - 配置中介绍的自定义数据源的方法,当IConfigurationProvider触发OnReload()事件时,这里的OnChange也就会被触发。string
使用PostConfigure可进行选项的后期配置:
services.PostConfigure<OrderServiceOptions>(options => { options.MaxOrderCount += 20; });
为了防止应用程序读取到错误的配置,能够为选项添加验证。
选项验证有三种方式:
添加选项须要替换为AddOptions
//services.Configure<OrderServiceOptions>(configuration); services.AddOptions<OrderServiceOptions>().Bind(configuration).Configure(options => { configuration.Bind(options); }) .Validate(options => options.MaxOrderCount <= 100, "MaxOrderCount不能大于100");
调用ValidateDataAnnotations:
services.AddOptions<OrderServiceOptions>().Bind(configuration).Configure(options => { configuration.Bind(options); }) .ValidateDataAnnotations<OrderServiceOptions>();
为选项模型类添加Annotation:
public class OrderServiceOptions { [Range(0, 100)] public int MaxOrderCount { get; set; }; }
注册验证服务:
services.AddOptions<OrderServiceOptions>().Bind(configuration).Configure(options => { configuration.Bind(options); }) .Services.AddSingleton<IValidateOptions<OrderServiceOptions>,OrderServiceValidateOptions> ();
实现IValidateOptions:
public class OrderServiceValidateOptions : IValidateOptions<OrderServiceOptions> { public ValidateOptionsResult Validate(string name, OrderServiceOptions options) { if (options.MaxOrderCount > 100) { return ValidateOptionsResult.Fail("MaxOrderCount不能大于100"); } else { return ValidateOptionsResult.Success; } } }