選項介面 IOptionsSnapshot與IOptionsMonitor的區別 選項的後期配置 選項的驗證 在 ASP.NET Core筆記(3) 配置 中介紹了各種配置提供程式以及配置的讀取方式,但實際使用中,不推薦應用程式直接從一堆配置中讀取的做法,而是使用強類型綁定,將配置按組綁定到不同服務 ...
- 選項介面
- IOptionsSnapshot與IOptionsMonitor的區別
- 選項的後期配置
- 選項的驗證
在ASP.NET Core筆記(3) - 配置中介紹了各種配置提供程式以及配置的讀取方式,但實際使用中,不推薦應用程式直接從一堆配置中讀取的做法,而是使用強類型綁定,將配置按組綁定到不同服務所屬的類。使用這種方式可以讓配置方案遵守兩個重要的軟體工程原則:
- 介面分離原則 (ISP) 或封裝 – 依賴於配置設置的方案(類)僅依賴於其使用的配置設置。
- 關註點分離 – 應用的不同部件的設置不彼此依賴或相互耦合。
選項介面
ASP.NET Core選項模式常用的介面有
- IOptions
- IOptionsSnapshot
- IOptionsMonitor
IOptions在配置更改時無法對應變更選項的值,只能重啟應用。IOptionsSnapshot和IOptionsMonitor則具有這種能力。
選項可以作為服務在使用時被註入,下麵的代碼模擬了選項的使用場景,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>();
IOptionsSnapshot與IOptionsMonitor的區別
這裡註入時使用的是AddScoped作用域的方式,是因為使用了IOptionsSnapshot介面。IOptionsSnapshot的生命周期為作用域,會在每次請求時應重新讀取配置、更新選項。所以修改配置後,重新請求API,就可以看到最新的配置值。
如果嘗試選擇AddSingleton,由於OrderService單例的生命周期比IOptionsSnapshot更長,會直接拋出運行時異常。
而如果遇到既需要單例生命周期,還需要變更檢測的場景時怎麼辦呢?這時就需要用到IOptionsMonitor了。
IOptionsMonitor 和 IOptionsSnapshot 之間的區別在於:
- IOptionsMonitor 是一種單例服務,且可以監測配置的變更。
- IOptionsSnapshot 是一種作用域服務,併在構造 IOptionsSnapshot
對象時提供選項的快照。
IOptionsMonitor使用與IOptionsSnapshot類似,但取值變為CurrentValue。如果修改配置源,就會觸發OnChange方法:
_options.OnChange(option =>
{
Console.WriteLine($"配置更新了,最新的值是:{_options.CurrentValue.MaxOrderCount}");
});
IOptionsMonitor還可以結合ASP.NET Core筆記(3) - 配置中介紹的自定義數據源的方法,當IConfigurationProvider觸發OnReload()事件時,這裡的OnChange也就會被觸發。
選項的後期配置
使用PostConfigure可進行選項的後期配置:
services.PostConfigure<OrderServiceOptions>(options =>
{
options.MaxOrderCount += 20;
});
選項的驗證
為了防止應用程式讀取到錯誤的配置,可以為選項添加驗證。
選項驗證有三種方式:
- 直接註冊驗證函數
- DataAnnotations
- 實現IValidateOptions介面
直接註冊驗證函數
添加選項需要替換為AddOptions
//services.Configure<OrderServiceOptions>(configuration);
services.AddOptions<OrderServiceOptions>().Bind(configuration).Configure(options =>
{
configuration.Bind(options);
})
.Validate(options => options.MaxOrderCount <= 100, "MaxOrderCount不能大於100");
DataAnnotations
調用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; };
}
實現IValidateOptions介面
註冊驗證服務:
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;
}
}
}