只有累積,沒有奇蹟

2021年11月3日 星期三

[NETCore] ASP.NET Core 使用強型別取代 IOption 注入配置

前言
之前的 如何取得 appsettings.json 組態設定 文章中有介紹在 ASP.NET Core 中透過 IOptions 方法取得設定檔的方法,在需要用到的地方注入 IOptions 取得設定類別的資訊,相信使用上並不困難在 MSDN 官方推薦作法也是如此,但如果開發一陣子之後可以發現到處都是 IOptios 類別,這篇文章介紹如何使用擴充 IServiceCollection 的方法來降低對 IOptios 的依賴,若有問題或是錯誤的地方歡迎各方高手大大一起討論或給予指導

IOption
之首先先來簡單回顧  IOptions<T>  的傳統用法,透過微軟 MSDN 中 IOptions 介紹得知要使用前需先引用 Microsoft.Extensions.Options,為了方便快速了解差異性,這裡建立一個 ASP.NET Core Web 應用程式範例來說明,在新增完應用程式後在 appsetting.json 加入自己定義的  mySettings  設定資訊提供 Name 以及 Title 屬性
  1. "MySettings": {
  2. "Name": "Marcus",
  3. "Title": "9527"
  4. }
接著要取得設定檔的內容,這邊建立與 Config 內容欄位相同的強型別的 class 物件
  1. public class MySettings
  2. {
  3. public string Name { get; set; }
  4. public string Title { get; set; }
  5. }
在 ConfigureServices 中加入下列代碼,用意是將 appsettinss.json 中的資訊加載到 MySettings 中
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  4. services.AddOptions();
  5. services.Configure<MySettings>(Configuration.GetSection("MySettings"));
  6. }
接著就可以在 Value Controll 使用 IOptions<T> 取得設定檔的資訊,代碼如下
  1. public class ValuesController : ControllerBase
  2. {
  3. public MySettings _mySettings { get; set; }
  4.  
  5. public ValuesController(IOptions<MySettings> settings)
  6. {
  7. _mySettings = settings.Value;
  8. }
  9.  
  10. // GET api/values
  11. [HttpGet]
  12. public ActionResult<IEnumerable<string>> Get()
  13. {
  14. return new string[] { _mySettings.Name, _mySettings.Title };
  15. }

不使用 IOptions 注入
以上快速地回顧 IOptions<T> 的用法,就可以簡單使用 IOption<T> 取得 appsettings.json 設定資訊的方法,但是這意味著你的代碼與 IOptions 有著強制依賴的關係,你有多少 Controller 就需要在各別的 Controller 中都 using 所需要的 Microsoft.Extensions.Options,除非 appsettings.json 中的設定很常異動需要進行重新載入( 這時可以使用  IOptionMonitor  而不是 IOptions ),否則大部分的使用情境中 config 設定都是較少異動的,參考此文章之後有了新的解法,我們可以新增一個類別並針對 IServiceCollection 加入擴充方法,代碼如下
  1. public static class ServiceCollectionExtensions
  2. {
  3. public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
  4. {
  5. if (services == null) throw new ArgumentNullException(nameof(services));
  6. if (configuration == null) throw new ArgumentNullException(nameof(configuration));
  7.  
  8. var config = new TConfig();
  9. configuration.Bind(config);
  10. services.AddSingleton(config);
  11. return config;
  12. }
  13. }
這裡我們在 startup.cs 時手動使用  Microsoft.Extensions.Configuration.Binder  來綁定設定檔,並指定服務容器生命週期 (LifeTime) 為 Singleton,在 ASP.NET Core DI 預設提供的 Lifetime 有下列三種
  • Transient : 每次請求時都會產生新的 Instance
  • Scoped : 每個 http Request 都會產生一份 Instance
  • Singleton : 整個 Application 只會有一份 Instance
可以依據所需要情境作調整,如果想了解差異可以參考之前的文章 : 傳送門 

新增完擴充方法之後,接著下一步就是在 ConfigureServices 改用新增的擴充方法 confugurePOCO
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  4. services.AddOptions();
  5. services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
  6. //services.Configure<MySettings>(Configuration.GetSection("MySettings"));
  7. }
接著在回到要使用的地方也就是範例的 ValueController, 將 IOptions 依賴移除改為強行別的 MySettings
  1. public MySettings _mySettings { get; set; }
  2.  
  3. public ValuesController(MySettings settings)
  4. {
  5. _mySettings = settings;
  6. }
在重新執行應用程式,可以發現應用程式執行正常無誤
如果你對於擴充方法很熟悉,也可以針對自己的需求來自訂所需的方法簽章,例如新增一個 TConfig 參數做為繫結設定檔代碼如下
  1. public static class ServiceCollectionExtensions
  2. {
  3. public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration, TConfig config) where TConfig : class
  4. {
  5. if (services == null) throw new ArgumentNullException(nameof(services));
  6. if (configuration == null) throw new ArgumentNullException(nameof(configuration));
  7. if (config == null) throw new ArgumentNullException(nameof(config));
  8. configuration.Bind(config);
  9. services.AddSingleton(config);
  10. return config;
  11. }
  12. }
使用方式先 new 之後作為參數傳入
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc();
  4. var mySettings = new MySettings("foo");
  5. services.ConfigurePOCO(Configuration.GetSection("MySettings"), mySettings);
  6. }
或者是新增 Func<TConfig> 參數透過委派方法新增 TConfig 的 instance
  1. public static class ServiceCollectionExtensions
  2. {
  3. public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration, Func<TConfig> pocoProvider) where TConfig : class
  4. {
  5. if (services == null) throw new ArgumentNullException(nameof(services));
  6. if (configuration == null) throw new ArgumentNullException(nameof(configuration));
  7. if (pocoProvider == null) throw new ArgumentNullException(nameof(pocoProvider));
  8.  
  9. var config = pocoProvider();
  10. configuration.Bind(config);
  11. services.AddSingleton(config);
  12. return config;
  13. }
  14. }
使用方式如下
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //...
  4. services.ConfigurePOCO(Configuration.GetSection("MySettings"), () => new MySettings("foo"));
  5. //...
  6. }
如果想了解更多細節,可以參考 Strongly typed configuration in ASP.NET Core without IOptions<T> 取得更多資訊,希望透過以上的介紹,可以讓跟我有一樣困擾的開發者得到新的作法,Hope it helps :)

Related Posts:

  • [UnitTest] Visual Studio 2017 新增單元測試時沒有 NUnit 選項 ?前言 新筆電總是讓人充滿驚喜,在使用上除了要重新安裝常用的開發工具外,像是 Visual Studio & SQL Server..等必須工具,還有些常用的套件與小工具也要一併安裝,NUnit 是蠻常用的 Test Framwroek 之一,在寫測試時在要測試的 method 下按下右鍵 create Unit Tests,選擇要使用測試的 Test Framework 即可,在測試專案中預設只有 MSTest 選項,如果需要 NUnit… Read More
  • [PowerShell] 設定 IIS - 建立 Application Pool、WebSite前言 PowerShell是微軟公司開發的任務自動化和組態管理框架,相信有接觸過 CI / CD 的人都是聽過且用過這工具,今天就來簡單介紹如何使用 PowerShell 來建立 Application Pool 跟 WebSite 的過程 指令說明 輸入指令 相關指令可以參考 WebAdministration # import module Import-Module WebAdministration cd IIS:\AppPoo… Read More
  • [WEB API] 使用 Swagger 自動產生 WebAPI 技術文件Swagger 是什麼 以下是 Swagger 官網說明 “ Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API “  Swagger 是一個可以將你的 API 接口變成可視化的服務,透過 Swag… Read More
  • [UnitTest] Reflect.cs not found in NUnit問題 最近在新的專案寫 UnitTest 過程中,執行完後 Visual Studio 卻跳出 Source Not Fount : Reflect.cs not found 錯誤,但單元測試還是可以成功,如下圖 且透過 debug UnitTest 時發現測試的值也沒問題,經搜尋後發現是 Visual Studio 2017 IDE 設定問題,將,這篇文章簡單紀錄處理問題過程 處理方式 釐清問題 按下… Read More
  • [.NET] 伺服器認可通訊協定違規. Section=ResponseHeader Detail=CR 必須在 LF 之前問題 公司某個專案是使用 RestSharp 套件進行發送 Request 呼叫第三方的動作,今天在使用時忽然出現沒看過的錯誤訊息 伺服器認可通訊協定違規. Section=ResponseHeader Detail=CR 必須在 LF 之前 ,開發這麼多年來第一次看到此錯誤,筆記一下解決此問題的過程以表示對這問題的重視 處理方式 還原現場  先還原現場 Code 頗單純的,SendRequest 方法使用… Read More

1 則留言:

Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com