昨天提到 ASP.NET Core 內建的 IConfiguration 機制會依下列順序讀取設定

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. 使用者祕密
  4. 環境變數設定
  5. 命令列引數

這種設計可以做到部署後預設以 appsettings.json 為準,在特定主機上用環境變數覆寫設定,遇特殊狀況可臨時改傳 CLI 參數,實現高度彈性。而讀者 Yuna 問到:純 Console 有沒有這麼方便的機制可用? Sure, Of course, why not? 本想直接找篇有範例的文章連結回覆,但發現還真沒詳細介紹過做法,今天補上。

假設有 Console 應用程式範例如下:(註:專案需參照 Microsoft.Extensions.Configuration.Json、Microsoft.Extensions.Configuration.EnvironmentVariables、Microsoft.Extensions.Configuration.CommandLine 等程式庫)

using Microsoft.Extensions.Configuration;

IConfiguration config = new ConfigurationBuilder()
        // 指定由當下路徑的 appsettings.json 讀取
        // 若要依 .dll/.exe 路徑,可用 AppContext.BaseDirectory 
        // https://blog.darkthread.net/blog/net6-get-exe-path/
         .SetBasePath(Directory.GetCurrentDirectory())
         // 由 appsettings.json 讀取
         .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
         // 由 appsettings.Production.json 及 appsettings.Development.json 讀取
         /*
         .AddJsonFile(
            $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", 
            optional: true, reloadOnChange: true)
        */
         // .AddUserSecrets<Program>() 由使用者祕密讀取
         .AddEnvironmentVariables() // 使用環境變數
         .AddCommandLine(args) // 使用 CLI 參數
         .Build();

Console.WriteLine("MySetting = " + config["MySetting"]);

更動 .AddJsonFile()、.AddEnvironmentVariables()、.AddCommandLine(args) 順序,我們甚至可以改變覆寫優先權,但預設順序很符合實務需求,很少需要調整。

註:此處未包含從使用者祕密讀取,有興趣了解的同學可參考這篇:使用 dotnet user-secrets 儲存專案專屬秘密設定(API Key、密碼)

接著來實測。先準備一個 appsettings.json:

{
    "MySetting": "From appsettings.json"
}

分別測試預設行為、設環境變數及指定 CLI 參數三種呼叫方式,驗證可達成彈性指定不同設定值的目標:

打完收工。

【2025-02-13 更新】若可依預設順序套用設定,感謝 Alex 分享更簡單的做法:

var builder = Host.CreateApplicationBuilder(args);
var config = builder.Configuration;
Console.WriteLine(config["MySetting");

HostApplicationBuilder 會完成以下動作:參考

  • 將 ContentRootPath 設置為 GetCurrentDirectory()
  • 讀取 DOTNET_ 起首環境變數加入 IConfiguration
  • appsettings.jsonappsettings.[EnvironmentName].json 設定加入 IConfiguration
  • 當 EnvironmentName 為 Development 時,透過入口組件從 User Secrets 載入應用程式的 IConfiguration
  • 從環境變數中加載應用程式的 IConfiguration
  • 設定 ILoggerFactory 以記錄到主控台、偵錯和事件輸出
  • 當 EnvironmentName 為 Development 時,啟用在依賴注入容器上的範圍驗證

看了一下原始碼,其設定載入邏輯如下,有疑義時可參考:

internal static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args)
{
    IHostEnvironment env = hostingContext.HostingEnvironment;
    bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext);

    appConfigBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: reloadOnChange)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: reloadOnChange);

    if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 })
    {
        try
        {
            var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
            appConfigBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
        }
        catch (FileNotFoundException)
        {
            // The assembly cannot be found, so just skip it.
        }
    }

    appConfigBuilder.AddEnvironmentVariables();

    AddCommandLineConfig(appConfigBuilder, args);

    [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Calling IConfiguration.GetValue is safe when the T is bool.")]
    static bool GetReloadConfigOnChangeValue(HostBuilderContext hostingContext) => hostingContext.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true);
}

In this post, I introduce using ASP.NET Core’s IConfiguration in Console applications for flexible settings management. It prioritizes appsettings.json, environment variables, and CLI arguments, providing high flexibility. Detailed example code demonstrates the practical implementation for .NET Console apps.


Comments

# by Alex

我都是用 var builder = Host.CreateApplicationBuilder(args); var configuration = builder.Configuration;

# by Yuna

謝謝黑暗大大!

# by Jeffrey

to Alex, 感謝分享,已補充於本文。

# by 小黑

觀察黑大最近的程式碼大都使用 vscode 編輯,想問一下,若是既有專案是使用 Visual Studio 2022 建立的,其中方案內有數個專案,是由一個主要專案引用若干專案,這類的情境也可以使用 vscode 開發嗎?

# by 小黑

感謝黑大

Post a comment