dotnet core appSetting

在程式裡面調用應用程式設定值的方法

透過 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
// Program.cs
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>();

// StartUp.cs
public void ConfigureServices(IServiceCollection services)
{
// 將設定值與POCO類別mapping
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;
}

/// <summary>
/// 公司名稱
/// </summary>
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,這篇文章中很多回答都很棒,包含了他們回答的評論,我沒有辦法一一舉例說明,有興趣的可以去閱讀一下

參考連結

  1. ASP.NET Core 中的選項模式
  2. Strongly typed configuration in ASP.NET Core without IOptions
  3. ASP.NET Core—access Configuration from static class