Stories

Detail Return Return

C#.NET Configuration 全面解析:從多環境到強類型綁定實戰 - Stories Detail

簡介

ASP.NET Core 的配置系統旨在提供統一、靈活的方式來讀取應用程序設置。它具備以下特點:

  • 支持多種配置源:JSON、XML、INI、環境變量、命令行、內存、用户機密、數據庫、自定義等;
  • 層級合併與覆蓋:後添加的配置源會覆蓋前面的同名鍵;
  • 鍵名稱統一:默認使用 “冒號”分隔的層級鍵(如 Logging:LogLevel:Default);
  • 與 DI 整合:通過 IConfiguration 及 IOptions<T> 注入到服務中;
  • 動態重載:部分配置源(如 JSON 文件)支持文件更改時自動刷新。

整個流程通常是在程序啓動時通過 ConfigurationBuilder 構建一個 IConfigurationRoot,並將其註冊到依賴注入容器。

配置系統架構演進

graph LR
    A[.NET Framework] --> B[App.config/web.config]
    B --> C[System.Configuration]
    D[.NET Core+] --> E[統一配置模型]
    E --> F[多種配置源]
    E --> G[選項模式]
    E --> H[依賴注入集成]

配置系統演進:

  • .NET Framework 時代:基於 XMLapp.config/web.config,通過 ConfigurationManager訪問
  • .NET Core+ 時代:靈活的統一配置模型,支持多種配置源和格式

核心特性

  • 多源配置:

    • 支持多種配置提供程序(Providers),如 JSON、XML、INI、環境變量、命令行、Azure Key Vault 等。
    • 配置按添加順序合併,後添加的提供程序覆蓋前面的值。
  • 類型安全綁定:

    • 使用 Bind 方法或 Options Pattern 將配置映射到 C# 對象。
    • 示例:services.Configure<MySettings>(configuration.GetSection("MySettings"))
  • 熱加載(Hot Reload):

    • 支持文件更改時自動重新加載配置(如 appsettings.json)。
    • 示例:AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  • 環境特定配置:

    • 支持基於環境的配置文件,如 appsettings.Development.json
    • 示例:AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  • 依賴注入集成:

    • 通過 IOptions<T>、IOptionsSnapshot<T>IOptionsMonitor<T> 注入配置。
    • 示例:services.AddOptions<MySettings>()
  • 層次結構支持:

    • 支持嵌套配置(如 JSON 對象),通過 : 分隔符訪問。
    • 示例:configuration["Database:ConnectionString"]
  • 擴展性:

    • 支持自定義配置提供程序。
    • Azure Key Vault、Consul 等集成。
  • 安全性:

    • 支持從 Azure Key Vault 或環境變量加載敏感數據(如密碼、API 密鑰)。

核心接口與類

  • IConfiguration

    • 只讀接口,表示配置鍵值對集合。
    • 通過索引器 configuration["Section:Key"] 訪問。
  • IConfigurationRoot(繼承自 IConfiguration

    • 代表已構建完成的配置根,可調用 Reload() 觸發重新加載。
  • IConfigurationBuilder

    • 用於逐步添加各類配置源(Providers),最終通過 Build() 生成 IConfigurationRoot
  • IConfigurationProvider

    • 配置提供者接口,負責從具體源讀取鍵值並加載到內存;
  • IConfigurationSource

    • 配置提供者的“工廠”,負責創建對應的 IConfigurationProvider

在 ASP.NET Core 中,WebApplication.CreateBuilder(args) 會自動創建並添加常見配置源,然後將構建的 IConfiguration 註冊到服務容器中。

配置提供程序 (Providers)

  • JSON: .AddJsonFile("appsettings.json")
  • 環境變量: .AddEnvironmentVariables()
  • 命令行參數: .AddCommandLine(args)
  • Azure Key Vault: .AddAzureKeyVault()
  • 用户機密 (開發環境): .AddUserSecrets<Program>()

內置配置源

appsettings.json / appsettings.{Environment}.json

// appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning"
    }
  },
  "ConnectionStrings": {
    "Default": "Server=.;Database=MyApp;..."
  }
}
  • 默認會加載 appsettings.json,再加載 appsettings.Development.json(根據 ASPNETCORE_ENVIRONMENT 環境變量);
  • JSON 文件支持層級結構,且可設置 reloadOnChange: true 以監控文件變動。

環境變量

  • 讀取系統環境變量,鍵名以“__”(雙下劃線)代表層級分隔,例如 Logging__LogLevel__Default=Debug
  • 環境變量優先級高於 JSON

命令行參數

dotnet run --Logging:LogLevel:Default=Trace --MyOption:Sub=Value
  • 命令行參數形式必須是 --鍵=值,覆蓋所有前面加載的源。

其他常見源

  • INI 文件:builder.AddIniFile("config.ini");
  • XML 文件:builder.AddXmlFile("config.xml");
  • 內存字典:適合單元測試或運行時動態添加:
builder.AddInMemoryCollection(new Dictionary<string,string>{
  ["MyKey"]="MyValue"
});

配置優先級(從高到低)

  • 命令行參數
  • 環境變量
  • 用户機密 (開發)
  • appsettings.{Environment}.json
  • appsettings.json

基礎使用

// 獲取配置值
string connectionString = configuration["ConnectionStrings:DefaultConnection"];
string apiKey = configuration["ApiKey"];
int timeout = configuration.GetValue<int>("Timeout", 30);  // 獲取值,帶默認值

// 獲取配置節
IConfigurationSection databaseSection = configuration.GetSection("Database");
string server = databaseSection["Server"];
string database = databaseSection["Name"];

構建與註冊

在 Program.cs(最簡版)中:

var builder = WebApplication.CreateBuilder(args);
// builder.Configuration 已經包含:
// 1. appsettings.json
// 2. appsettings.{Env}.json
// 3. 環境變量
// 4. 命令行

// 可繼續添加自定義源
builder.Configuration
       .AddJsonFile("custom.json", optional:true, reloadOnChange:true)
       .AddUserSecrets<Program>();

// 註冊 Options
builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings"));

var app = builder.Build();  

強類型綁定(Options 模式)

直接從 IConfiguration 獲取字符串較為零散,推薦使用 Options 模式將配置映射為 POCO 對象,並通過 DI 獲取。

定義配置對象

public class MySettings
{
    public string Url { get; set; }
    public int RetryCount { get; set; }
    public NestedSettings Nested { get; set; }
}
public class NestedSettings
{
    public bool Enabled { get; set; }
}

對應 appsettings.json

"MySettings": {
  "Url": "https://api.example.com",
  "RetryCount": 3,
  "Nested": {
    "Enabled": true
  }
}

在 Program.cs 中綁定

builder.Services
       .AddOptions<MySettings>()
       .Bind(builder.Configuration.GetSection("MySettings"))
       .ValidateDataAnnotations()   // 可選:啓用數據註解驗證
       .Validate(s => s.RetryCount >= 0, "RetryCount must be non-negative");

在業務中注入使用

public class MyService
{
    private readonly MySettings _settings;
    public MyService(IOptions<MySettings> opts)
    {
        _settings = opts.Value;
    }
    public void Run() {
        Console.WriteLine(_settings.Url);
    }
}

也可注入 IOptionsMonitor<T>(支持變更監聽)或 IOptionsSnapshot<T>(每次請求新的快照,僅限 Scoped 服務)。

動態重載與變更監聽

對於支持 reloadOnChange: true 的配置源(如 JSON 文件、環境變量不支持文件監控),IOptionsMonitor<T> 可感知配置變更並觸發回調:

services.AddOptions<MySettings>()
        .Bind(config.GetSection("MySettings"))
        .ValidateDataAnnotations();

services.AddSingleton<IHostedService, MonitorService>();

public class MonitorService : BackgroundService
{
    private readonly IOptionsMonitor<MySettings> _monitor;
    public MonitorService(IOptionsMonitor<MySettings> monitor)
        => _monitor = monitor;

    protected override Task ExecuteAsync(CancellationToken ct)
    {
        _monitor.OnChange(s => 
            Console.WriteLine($"New URL: {s.Url}")
        );
        return Task.CompletedTask;
    }
}
user avatar kinra Avatar tecdat Avatar zhishuangdehuoguo_dpf8ay Avatar wanglizhi_5dd4059a702d2 Avatar
Favorites 4 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.