dotnet core appSetting


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

透過 POCO 類別調用設定值

一般來說我們的應用程式設定值都放在appsettings.json,這支 Json 檔案還可以利用Configuration Transform這一套工具,在 Visual Studio IDE 裡面直接設定各種環境的設定檔,這一個部分就不在這次討論之中,有興趣的自行再研究

為了要能夠在程式中強型別的使用設定,通常會透過建立一個 POCO 類別,假設有兩個設定值 A 跟 B,則類別可以這樣撰寫

public class AppSettingConfig
{
    public string A {get; set;}
    public string B {get; set;}
}

將應用程式設定值檔案,從預設的appsettings.json,調整為_config/app.config.json

要不要變更應用程式設定值的 json 檔案路徑,看個人習慣,也可直接使用預設即可

// 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 的建構式中注入並使用

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 的差別就在於,重新讀取頁面的時候,設定值有沒有跟著實際設定改動

public DemoController(IOptionsMonitor<AppSettingConfig> config)
{
    _config = config.CurrentValue;
}

可是一般應用程式設定值比較不常變動吧,常常會變動的話我們應該都是會放在資料庫裏面,而不是透過實際的文字檔案更動

於 Controller 直接注入 POCO

在上面的兩種方式,POCO 始終都透過 IOption 一起使用,POCO 都不 POCO 了,所以就有人希望直接在 Controller 裡面注入 POCO 類別,而不需要在 using 額外的命名空間來使用 IOptions

所以為 ServiceCollection 加上擴充方法,就可以直接注入了,原文在此,程式碼如下

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也就只需要加入下面這行

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.ConfigurePOCO<AppSettingConfig>(Configuration);
    // ...
}

就可以直接在 Controller 使用

public class DemoController : Controller
{
    private AppSettingConfig _config;
    public DemoController(AppSettingConfig config)
    {
        _config = config;
    }
    public IActionResult Index()
    {
        ViewBag.A = _config.A;
        return View();
    }
}

現在實務上的用法

因為上面的方法,如果在很多地方都需要用,不可避免的就是每個地方都要給它注入一下,用起來感覺就不是那麼的方便。

appSetting.json

{
  "MyCompanyName": "我的公司名稱"
}

AppSettingConfig.cs

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

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