一.概述 本章講的選項模式是對Configuration配置的功能擴展。 講這篇時有個專用名詞叫“選項類(TOptions)” 。該選項類作用是指:把選項類中的屬性與配置來源中的鍵關聯起來。舉個例,假設json文件有個Option1鍵,選項類中也有個叫Option1的屬性名,經過選項配置,這樣就能把 ...
一.概述
本章講的選項模式是對Configuration配置的功能擴展。 講這篇時有個專用名詞叫“選項類(TOptions)” 。該選項類作用是指:把選項類中的屬性與配置來源中的鍵關聯起來。舉個例,假設json文件有個Option1鍵,選項類中也有個叫Option1的屬性名,經過選項配置,這樣就能把json中的鍵的值映射到選項類屬性值中。也可以理解在項目應用中,把一個json文件序列化到.net類。
1.1選項介面介紹
在官方文檔中選項介面有很多,這裡列舉了這些選項介面。所有選項介面基本都繼承了TOptions介面。
// Used for notifications when TOptions instances change public interface IOptionsMonitor<out TOptions> { // // 摘要: // Returns the current TOptions instance with the Microsoft.Extensions.Options.Options.DefaultName. TOptions CurrentValue { get; } //... } // Used to create TOptions instances public interface IOptionsFactory<TOptions> where TOptions : class, new() { // // 摘要: // Returns a configured TOptions instance with the given name. TOptions Create(string name); } // Represents something that configures the TOptions type. Note: These are run before all public interface IConfigureOptions<in TOptions> where TOptions : class { // // 摘要: // Invoked to configure a TOptions instance. // // 參數: // options: // The options instance to configure. void Configure(TOptions options); } public interface IPostConfigureOptions<in TOptions> where TOptions : class { // // 摘要: // Invoked to configure a TOptions instance. // // 參數: // name: // The name of the options instance being configured. // // options: // The options instance to configured. void PostConfigure(string name, TOptions options); } public interface IConfigureNamedOptions<in TOptions> : IConfigureOptions<TOptions> where TOptions : class { // // 摘要: // Invoked to configure a TOptions instance. // // 參數: // name: // The name of the options instance being configured. // // options: // The options instance to configure. void Configure(string name, TOptions options); } // Used by IOptionsMonitor<TOptions> to cache TOptions instances. public interface IOptionsMonitorCache<TOptions> where TOptions : class { // // 摘要: // Clears all options instances from the cache. void Clear(); // // 摘要: // Gets a named options instance, or adds a new instance created with createOptions. // // 參數: // name: // The name of the options instance. // // createOptions: // The func used to create the new instance. // // 返回結果: // The options instance. TOptions GetOrAdd(string name, Func<TOptions> createOptions); // // 摘要: // Tries to adds a new option to the cache, will return false if the name already // exists. // // 參數: // name: // The name of the options instance. // // options: // The options instance. // // 返回結果: // Whether anything was added. bool TryAdd(string name, TOptions options); // // 摘要: // Try to remove an options instance. // // 參數: // name: // The name of the options instance. // // 返回結果: // Whether anything was removed. bool TryRemove(string name); } // Used to access the value of TOptions for the lifetime of a request public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new() { // // 摘要: // Returns a configured TOptions instance with the given name. TOptions Get(string name); } //Used to retrieve configured TOptions instances public interface IOptions<out TOptions> where TOptions : class, new() { // // 摘要: // The default configured TOptions instance TOptions Value { get; } }View Code
(1) IOptionsMonitor<TOptions>
IOptionsMonitor<TOptions>用於TOptions實例更改時的通知,用於管理 TOptions選項類 。該IOptionsMonitor<TOptions>支持以下方案:
(1) 更改通知。當配置文件發生修改時,會監聽同步到選項類。
(2) 命名選項。IConfigureNamedOptions支持命名選項。介面繼續關係 IConfigureNamedOptions:IConfigureOptions
(3) 重新載入配置。通過 IOptionsSnapshot 重新載入配置數據,IOptionsMonitor也支持該功能。 介面繼續關係IOptionsSnapshot :IOptions
(4) 選擇性選項失效 (IOptionsMonitorCache<TOptions>)。
(2) 其它介面
IOptionsFactory<TOptions> 負責產生TOptions選項實例,它具有單個 Create 方法。
預設實現採用所有已註冊 IConfigureOptions<TOptions> 和 IPostConfigureOptions<TOptions> 並首先運行所有配置(所有的來源配置),
然後才進行選項後期配置IPostConfigureOptions<TOptions> 。
IOptionsMonitorCache<TOptions>用於緩存TOptions實例。
1.2 常規選項配置
TOptions選項類必須為包含公共無參數構造函數的非抽象類。下麵示例中選項類MyOptions具有兩種屬性:Option1
和 Option2
。 設置預設值為可選,但以下示例中的類構造函數設置了 Option1
的預設值。 Option2
具有通過直接初始化屬性設置的預設值。
public class MyOptions { public MyOptions() { // Set default value. Option1 = "value1_from_ctor"; } public string Option1 { get; set; } public int Option2 { get; set; } = 5; }
//將MyOptions類已通過Configure添加到服務容器,並綁定到配置IConfiguration上 //Registers a configuration instance which TOptions will bind against. services.Configure<MyOptions>(Configuration);
private readonly MyOptions _options;
//OtherPages/Page1 public Page1Model( IOptionsMonitor<MyOptions> optionsAccessor) { _options = optionsAccessor.CurrentValue; } public void OnGet() { var option1 = _options.Option1; var option2 = _options.Option2; var SimpleOptions = $"option1 = {option1}, option2 = {option2}"; }
// 此時SimpleOptions值:"option1 = value1_from_ctor, option2 = 5"
//下麵在appsettings.json 文件添加 option1 和 option2 的值。 "option1": "value1_from_json", "option2": -1,
當配置文件appsettings.json中option1和option2鍵的值改變後,MyOptions 選項類中的屬性option1和option2的值也會改變。 下麵再次運行OtherPages/Page1
//此時SimpleOptions的值為:"option1 = value1_from_json, option2 = -1"
為什麼MyOptions類中option1,option2會取到appsettings.json文件中的值呢?因為MyOptions選項類註入到Iconfiguration服務後與appsettings.json文件中鍵相同,形成了映射。
1.3 通過委托配置簡單選項
使用委托設置選項值。 此示例應用使用 MyOptionsWithDelegateConfig 類 ,這裡仍然是使用相同的鍵Option1,Option2。 它通過 MyOptionsWithDelegateConfig 使用委托來配置綁定。
public class MyOptionsWithDelegateConfig { public MyOptionsWithDelegateConfig() { // Set default value. Option1 = "value1_from_ctor"; } public string Option1 { get; set; } public int Option2 { get; set; } = 5; }
services.Configure<MyOptions>(Configuration); //第二個註入服務 services.Configure<MyOptionsWithDelegateConfig>(myOptions => {
// 在Page1Model構造方法中生成MyOptionsWithDelegateConfig實例時調用 myOptions.Option1 = "value1_configured_by_delegate"; myOptions.Option2 = 500; });
public Page1Model( IConfiguration configuration, IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, IOptionsMonitor<MyOptions> optionsAccessor ) { _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue; _options = optionsAccessor.CurrentValue; Configuration = configuration; } public IConfiguration Configuration { get; } private readonly MyOptions _options; private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig; public string BindGUIDMsg { get; set; } public void OnGet() { BindGUIDMsg = $"option1 = {_options.Option1}, option2 = {_options.Option2}"; BindGUIDMsg += "</br>"; BindGUIDMsg += $"delegate_option1 = {_optionsWithDelegateConfig.Option1}, " + $"delegate_option2 = {_optionsWithDelegateConfig.Option2}"; }
每次調用 Configure 都會將 IConfigureOptions<TOptions> 服務添加到服務容器。 在前面的示例中,Option1 和 Option2 的值同時在 appsettings.json 中指定,但 Option1 和 Option2 的值被配置的委托替代。
當啟用多個配置服務時,指定的最後一個配置源優於其他源,由其設置配置值。 運行應用時,頁面模型的 OnGet
方法返回顯示選項類值的字元串:
// myOptions實例取值如下: SimpleOptions:option1 = -1,option2 = 5 // MyOptionsWithDelegateConfig實例取值如下: delegate_option1 = value1_configured_by_delegate,delegate_option2 = 500
1.4 子選項配置
當配置文件中的子節點需要與選項類進行關聯映射時,可以通過服務註入bind到指定的Configuration節點。在以下代碼中,已向服務容器添加第三個 IConfigureOptions<TOptions> 服務。 它將 MySubOptions 綁定到 appsettings.json 文件的 subsection 部分:
"Option1": "value1_from_json", "Option2": -1, "subsection": { "suboption1": "subvalue1_from_json", "suboption2": 200 }
public class MySubOptions { public MySubOptions() { // Set default values. SubOption1 = "value1_from_ctor"; SubOption2 = 5; } public string SubOption1 { get; set; } public int SubOption2 { get; set; } }
//第三個IConfigureOptions<TOptions>註入服務 services.Configure<MySubOptions>(Configuration.GetSection("subsection"));
//OtherPages/Page1 public Page1Model( IConfiguration configuration, IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, IOptionsMonitor<MyOptions> optionsAccessor, IOptionsMonitor<MySubOptions> subOptionsAccessor ) { _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue; _options = optionsAccessor.CurrentValue; _subOptions = subOptionsAccessor.CurrentValue; Configuration = configuration; } public IConfiguration Configuration { get; } private readonly MyOptions _options; private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig; private readonly MySubOptions _subOptions;
// OnGet方法 SubOptions = $"subOption1 = {_subOptions.SubOption1}, subOption2 = {_subOptions.SubOption2}"
//運行應用時,OnGet 方法返回顯示子選項類值的字元串: // MySubOptions實例取值如下: subOption1 = subvalue1_from_json,subOption2 = 200
1.5 IConfigureNamedOptions選項命名
IConfigureNamedOptions:是用於對選項類在註入服務時,進行命名。下麵是把MyOptions選項類註入到服務,並取了別名named_options_1。 如下所示:
services.Configure<MyOptions>("named_options_1", Configuration);
//在要使用的頁面,如下所示: private readonly MyOptions _named_options_1; public IndexModel( IOptionsSnapshot<MyOptions> namedOptionsAccessor) { _named_options_1 = namedOptionsAccessor.Get("named_options_1"); }
// IOptionsSnapshot源碼 public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new() { // // 摘要: // Returns a configured TOptions instance with the given name. TOptions Get(string name); }
1.6 ConfigureAll
上面介紹的選項類,在註入服務時都是使用的services.Configure,它是針對選項類的當前實例,例如:在page1和page2都使用了實例MyOptions( private readonly MyOptions _options)但它們屬於不同的實例。
//使用 ConfigureAll 方法配置所有選項實例 services.ConfigureAll<MyOptions>(myOptions => { //所有MyOptions實例配置 Option1的值 myOptions.Option1 = "ConfigureAll replacement value"; });
//添加代碼後運行示例應用將產生以下結果: named_options_1: option1 = ConfigureAll replacement value, option2 = -1 named_options_2: option1 = ConfigureAll replacement value, option2 = 5
總結:
選項模式是對Configuration配置的功能擴展,主要用於把json文件序列化到.net類(選項類)。通過註入services. Configure或services.ConfigureAll把選項類註入到服務並綁定到Configuration上。 選項這篇還有其它功能如:選項後期配置( IPostConfigureOptions), 啟動期間訪問選項, 選項驗證等,詳細瞭解查看官網
參考文獻
官方資料:asp.net core 選項