在前面的文章中,我們介紹過將appsetting等配置文件映射到實體的的方式
https://www.cnblogs.com/fei686868/p/16779249.html
這裏呢,我們介紹關於選項的另一種用法,就是通過IOptions等選項來使用。
他們的區別呢,以前那種是隻實現映射,如果要注入,需要自己寫注入代碼;但使用IOptions等方式呢,是自動注入了,我們無需再寫注入代碼,
顯得更簡潔,同時呢,擴展性更強。
本文示例環境:netcore3.1
爲了演示代碼,我們在appsetting.json中新增一個配置和實體
"Position": { "Title": "這個是標題", "Name": "這個是名稱" }
public class PositionOptions { public const string Position = "Position"; //定義節點名稱,與配置對應。這邊定義只是爲了方便管理,不用到處寫字符串 public string Title { get; set; } public string Name { get; set; } }
我們先看個簡單的寫法:
services.Configure<實體名稱>(Configuration.GetSection("配置文件中的節點名稱"));
這裏我們採用的是services自帶的Configure<>方法進行處理。
下面上實際代碼:
Startup.cs中配置
public void ConfigureServices(IServiceCollection services) { services.Configure<PositionOptions>(Configuration.GetSection(PositionOptions.Position)); //映射和注入 }
應用:
public class PositionController : Controller { private readonly PositionOptions _positionOptions; public PositionController(IOptions<PositionOptions> options) //通過IOption實現注入 { _positionOptions = options.Value; //獲取對應的Value即可 } public IActionResult Index() { string str = _positionOptions.Name; //這邊就能獲取到配置的Name了 return View(); } }
上面我們採用IOptions對象來處理,該方式呢,有個注意點:
不會讀取在應用啓動後對 JSON 配置文件所做的更改
就是啓動時讀取而已,如果配置文件改了,不會熱重載。但是在現實中,我們該配置,那還真會有。咋整?
選項有3種接口模式:
1、IOptions<TOptions>
不支持熱重載
不支持命名選項(下面會講什麼是命名選項)
註冊爲單一實例且可以注入到任何服務生存期
2、IOptionsSnapshot<TOptions>
支持熱重載,就是配置文件修改後,會更新。
註冊爲Scope類型,因此無法注入到單一實例服務
支持命名選項
3、IOptionsMonitor<TOptions>
用於檢索選項並管理 TOptions
實例的選項通知
註冊爲單一實例且可以注入到任何服務生存期。
支持更改通知、命名選項、熱重載
不管用什麼方式,不影響Startup.cs中服務注入的Configure 方法的寫法。
對於日常項目應用來說,主要就是熱重載的區別。不同方式,性能影響也不太一樣。雖然有時候可以忽略性能差異。
有些配置是啓動後,就不需要再修改的,可以採用IOptions。否則,請使用後面兩種。
但相對來說,第3種更適合一點。
我們看看寫法
IOptionsSnapshot 寫法
public class PositionController : Controller { private readonly PositionOptions _positionOptions; public PositionController(IOptionsSnapshot<PositionOptions> options) //通過IOption實現注入 { _positionOptions = options.Value; //獲取對應的Value即可 } public IActionResult Index() { string str = _positionOptions.Name; //這邊就能獲取到配置的Name了 return View(); } }
IOptionsMonitor 寫法
public class PositionController : Controller { private readonly PositionOptions _positionOptions; public PositionController(IOptionsMonitor<PositionOptions> options) //通過IOption實現注入 { _positionOptions = options.CurrentValue; //獲取對應的Value即可 } public IActionResult Index() { string str = _positionOptions.Name; //這邊就能獲取到配置的Name了 return View(); } }
三者,寫法基本相同。
那我們先做個小總結
1、IOptions ,註冊爲單例,不支持熱重載。
2、IOptionsSnapshot,註冊爲Scope範圍,支持熱重載
3、IOptionsMonitor,註冊爲單例,支持熱重載。
下面我們再介紹下命名選項的情況,僅 IOptionsSnapshot和IOptionsMonitor 二者支持
我們換個例子,改下配置
{ "班級情況": { "1班": { "StudentCount": 50, "AvgScore": 80 }, "2班": { "StudentCount":60, "AvgScore": 90 } } }
加入配置是這樣的,那我們需要分別獲取1班和2班的學生數和平均分,怎麼獲取?
我們分析這種情況,出現了同層級,key名稱不一樣(1班,2班,這就是命名選項,同層級,不同key),而每個key對象的子內容是裏面是格式是一樣的。
我們就這麼寫,定義實體
public class ClassData {
public const string NodeName = "班級情況"; public const string ClasName1 = "1班"; public const string ClassName2 = "2班"; public int StudentCount { get; set; } public int AvgScore { get; set; } }
實體中,我們定義了兩個變量與節點一一對應
注入的時候是有變化的
services.Configure<ClassData>( ClassData.ClassName1,Configuration.GetSection("班級情況:1班")); services.Configure<ClassData>(ClassData.ClassName2, Configuration.GetSection("班級情況:2班"));
看到了沒,得寫2個,分別寫。實體類型都一樣,但是 Configure方法的name參數不一樣。
應用端:
private readonly ClassData _classData1;//1班 private readonly ClassData _classData2;//2班 public PositionController(IOptionsSnapshot<ClassData> options) //通過IOption實現注入 { _classData1 = options.Get(ClassData.ClassName1); //分別獲取定義的name對應的數據 _classData2 = options.Get(ClassData.ClassName2); }
再獲取數據時,需要用這種方式來獲取。
看起來是一小點的知識,其實在很多組件封裝上很實用。比如Abp就很多Configure方法,自己用多了,就更能理解了
以上,就是關於選項的一些小應用和總結。
更多分享,請大家關注我的個人公衆號: