在程式裡面調用應用程式設定值的方法
透過 POCO 類別調用設定值
一般來說我們的應用程式設定值都放在appsettings.json
,這支 Json 檔案還可以利用Configuration Transform這一套工具,在 Visual Studio IDE 裡面直接設定各種環境的設定檔,這一個部分就不在這次討論之中,有興趣的自行再研究
為了要能夠在程式中強型別的使用設定,通常會透過建立一個 POCO 類別,假設有兩個設定值 A 跟 B,則類別可以這樣撰寫
1 2 3 4 5
| public class AppSettingConfig { public string A {get; set;} public string B {get; set;} }
|
將應用程式設定值檔案,從預設的appsettings.json
,調整為_config/app.config.json
要不要變更應用程式設定值的 json 檔案路徑,看個人習慣,也可直接使用預設即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostContext, config) => { var env = hostContext.HostingEnvironment; config.SetBasePath(Path.Combine(env.ContentRootPath, "_config")) .AddJsonFile(path: "app.config.json", optional: true, reloadOnChange: true); }) .UseStartup<Startup>();
public void ConfigureServices(IServiceCollection services) { services.Configure<AppSettingConfig>(Configuration); }
|
IOptions
接下來就是在 Controller 的建構式中注入並使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class DemoController : Controller { private AppSettingConfig _config; public DemoController(IOptions<AppSettingConfig> config) { _config = config.Value; } public IActionResult Index() { ViewBag.A = _config.A; return View(); } }
|
IOptionMonitor
改用 IOptionMonitor 的話,建構式注入的方法如下,跟 IOption 的差別就在於,重新讀取頁面的時候,設定值有沒有跟著實際設定改動
1 2 3 4
| public DemoController(IOptionsMonitor<AppSettingConfig> config) { _config = config.CurrentValue; }
|
可是一般應用程式設定值比較不常變動吧,常常會變動的話我們應該都是會放在資料庫裏面,而不是透過實際的文字檔案更動
於 Controller 直接注入 POCO
在上面的兩種方式,POCO 始終都透過 IOption 一起使用,POCO 都不 POCO 了,所以就有人希望直接在 Controller 裡面注入 POCO 類別,而不需要在 using 額外的命名空間來使用 IOptions
所以為 ServiceCollection 加上擴充方法,就可以直接注入了,原文在此,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static class ServiceCollectionExtensions { public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new() { if (services == null) throw new ArgumentNullException(nameof(services)); if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig(); configuration.Bind(config); services.AddSingleton(config); return config; } }
|
這樣的話,在StartUp.cs
也就只需要加入下面這行
1 2 3 4 5 6
| public void ConfigureServices(IServiceCollection services) { services.ConfigurePOCO<AppSettingConfig>(Configuration); }
|
就可以直接在 Controller
使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class DemoController : Controller { private AppSettingConfig _config; public DemoController(AppSettingConfig config) { _config = config; } public IActionResult Index() { ViewBag.A = _config.A; return View(); } }
|
現在實務上的用法
因為上面的方法,如果在很多地方都需要用,不可避免的就是每個地方都要給它注入一下,用起來感覺就不是那麼的方便。
appSetting.json
1 2 3
| { "MyCompanyName": "我的公司名稱" }
|
AppSettingConfig.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class AppSettingConfig { private AppSettingConfig(){}
private static readonly Lazy<AppSettingConfig> _instance = new Lazy<AppSettingConfig>(new AppSettingConfig()); public static AppSettingConfig Instance => _instance.Value;
private IConfiguration _config; public void Init(IConfiguration config) { _config = config; }
private string GetValue(string key, string defaultValue = "") { return _config.GetSection(key).Value ?? defaultValue; }
public string MyCompanyName => GetValue("MyCompanyName");
}
|
startup.cs
1 2 3 4 5 6 7 8 9
| public class Startup { public Startup(Iconfiguration configuration) { Configuration = configuration; AppSettingConfig.Instance.Init(configuration); } }
|
其他人的作法
目前專案上的用法是這樣的,一樣的用法可以參考這一篇ASP.NET Core—access Configuration from static class,這篇文章中很多回答都很棒,包含了他們回答的評論,我沒有辦法一一舉例說明,有興趣的可以去閱讀一下
參考連結
- ASP.NET Core 中的選項模式
- Strongly typed configuration in ASP.NET Core without IOptions
- ASP.NET Core—access Configuration from static class