在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; } } }