上一篇 ASP.NET Core - 選項系統之選項配置 中提到 IOptions、IOptionsMonitor 和 IOptionsSnapshot 三個介面,通過這三個介面都可以從依賴註入容器中解析出已經配置的選項類,在我們通過 Configure 方法配置選項時,這三個介面會被同時註冊,但三 ...
上一篇 ASP.NET Core - 選項系統之選項配置 中提到 IOptions
1. IOptions
- IOptions
對象的生命周期是 Singleton (單例),它可以在任意地方進行註入使用 - 該介面對象在第一次使用的時候被實例化,並且選項類中的內容會一直保持不變,前面也提過選項類內容可以在配置來源修改之後更新,但是通過 IOption
解析的選項類不會隨著更新而改變 - IOptions
介面不支持命名選項模式,它是沒有 get 方法的,也並不會預設讀取第一個,它只能讀取 String.Empty 預設命名的選項,如果沒有配置預設選項的話,雖然也能解析出 Options 選項類對象,但是對象的屬性都是相應類型的預設值(引用類型是 null,值類型是 0,其他的也都是相應類型的預設值)
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptions<BlogOptions> options)
{
// 通過 IOptions<TOptions> 介面的 Value 屬性讀取選項類
// 選項類始終是程式啟動時載入的值,不會改變
_blogOptions = options.Value;
}
}
2. IOptionsMonitor
- IOptionsMonitor
對象的生命周期是 Scoped(作用域),Scoped 生命周期的特點是不能註入到 Singleton 服務中 - 在作用域中(最常見的一次Http請求),創建 IOptionsSnapshot
對象實例時,會從配置中讀取最新選項值作為快照,併在當前作用域中始終使用該快照。也就是說一次請求中選項類內容保持不變,但是不同請求中可能因為配置來源的修改而不同 - IOptionsMonitor
支持命名選項
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptionsSnapshot<BlogOptions> optionsSnapshot)
{
// IOptionsSnapshot<TOptions> 可以通過 Value 屬性讀取預設的命名的選項類, Options 對象實例創建時讀取的配置快照
_blogOptions = optionsSnapshot.Value;
// 也可以通過 Get 方法獲取某一個命名選項,沒有指定命名時,預設命名為 string.Empty
//_blogOptions = optionsSnapshot.Get(string.Empty);
}
}
3. IOptionsSnapshot
- IOptionsSnapshot
對象的生命周期也是 Singleton (單例) - 通過 IOptionsSnapshot
介面註入的對象每次讀取選項值時,都是從配置中讀取最新選項值,能夠實時獲取配置來源的更改 - 該介面支持命名選項模式
- 除了可以查看 TOptions 的值,還可以監控 TOptions 配置的更改,支持重新載入配置(CurrentValue),並當配置發生更改時,進行通知(OnChange),支持緩存與緩存失效 (IOptionsMonitorCache
),每次調用實例的 CurrentValue 時,會先檢查緩存(IOptionsMonitorCache )是否有值,如果有值,則直接用,如果沒有,則從配置中讀取最新選項值,並記入緩存。當配置發生更改時,會將緩存清空。
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptionsMonitor<BlogOptions> optionsMonitor)
{
// IOptionsMonitor<TOptions> 介面沒有 Value 屬性,通過 CurrentValue 獲取選項類對象,
// 每次調用 CurrentValue都會實時讀取配置源,始終是最新配置的值
_blogOptions = optionsMonitor.CurrentValue;
// 該介面也支持通過 Get 方法獲取命名選項
_blogOptions = optionsMonitor.Get(string.Empty);
// 可以通過 OnChange 註冊事件,當配置被載入時會觸發事件
optionsMonitor.OnChange(OnOptionsChange);
}
[HttpGet]
public Task<BlogOptions> Get()
{
return Task.FromResult(_blogOptions);
}
private void OnOptionsChange(BlogOptions options)
{
Console.WriteLine(JsonSerializer.Serialize(options));
}
}
啟動應用,調用一次 Get 介面,在 Api 控制器構造函數中註冊了配置載入觸發事件,之後修改 appsettings.json 配置文件中選項類對於的配置節點內容,可以看到事件觸發,控制臺中輸出了改變之後的選項類內容。
4. 三個介面的選項讀取機制演示
三個介面解析的選項類的差別,可以通過以下測試清楚得看出:
配置文件中初始選項節點如下:
"Blog": {
"Title": "ASP.NET Core Options11",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
這裡為了方便看出 Scoped 生命周期 IOptionSnapeshoot
public class OptionController : ControllerBase
{
private readonly IOptions<BlogOptions> _blogOptions;
private readonly IOptionsSnapshot<BlogOptions> _blogSnapshotOptions;
private readonly IOptionsMonitor<BlogOptions> _blogMonitorOptions;
public OptionController(
IOptions<BlogOptions> options,
IOptionsSnapshot<BlogOptions> optionsSnapshot,
IOptionsMonitor<BlogOptions> optionsMonitor
)
{
// 註意這裡不能再把選項類對象先讀取出來,否則選項類對象也不會再改變了
_blogOptions = options;
_blogSnapshotOptions = optionsSnapshot;
_blogMonitorOptions = optionsMonitor;
}
[HttpGet]
public Task Get()
{
Console.WriteLine("第一次讀取配置:");
Console.WriteLine("IOptions<TOptions>:" + JsonSerializer.Serialize(_blogOptions.Value));
Console.WriteLine("IOptionsSnapshot<TOptions>:" + JsonSerializer.Serialize(_blogSnapshotOptions.Value));
Console.WriteLine("IOptionsMonitor<TOptions>:" + JsonSerializer.Serialize(_blogMonitorOptions.CurrentValue));
Console.WriteLine("請修改配置文件!");
Console.ReadKey();
Console.WriteLine("第二次讀取配置:");
Console.WriteLine("IOptions<TOptions>:" + JsonSerializer.Serialize(_blogOptions.Value));
Console.WriteLine("IOptionsSnapshot<TOptions>:" + JsonSerializer.Serialize(_blogSnapshotOptions.Value));
Console.WriteLine("IOptionsMonitor<TOptions>:" + JsonSerializer.Serialize(_blogMonitorOptions.CurrentValue));
return Task.CompletedTask;
}
}
之後啟動應用調用 Get 介面,併在過程中將配置文件內容修改為以下:
"Blog": {
"Title": "ASP.NET Core Options222",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
可以看到控制台的輸出中,第二次讀取配置的時候,IOptionsMonitor
之後不要關閉應用,再調一次 Get 介面,併在過程中再次修改配置如下:
"Blog": {
"Title": "ASP.NET Core Options333",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
這一次的 Get 請求的輸出結果如下:
可以看到 IOptionsMonitor
參考文章:
ASP.NET Core 中的選項模式 | Microsoft Learn
選項模式 - .NET | Microsoft Learn
面向 .NET 庫創建者的選項模式指南 - .NET | Microsoft Learn
理解ASP.NET Core - 選項(Options)
ASP.NET Core 系列:
目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 選項系統之選項配置