共用方式為


.NET 中的組態

.NET 中的組態是使用一或多個 組態提供者來執行,。 設定提供者使用各種設定來源,從鍵值對讀取設定資料。

注意

如需設定 .NET 執行時間本身的相關信息,請參閱 .NET 執行時間組態設定

概念和抽象概念

假設有一或多個組態來源,IConfiguration 類型會提供組態數據的統一檢視。 組態是只讀的,而且設定模式的設計不是以程式設計方式可寫入的。 IConfiguration 介面是所有組態來源的單一表示法,如下圖所示:

『IConfiguration』 介面是所有組態來源的單一表示法。

設定主控台應用程式

使用 dotnet 新 指令範本或 Visual Studio 建立的 .NET 控制台應用程式預設 不會 暴露設定功能。 若要在新的 .NET 控制台應用程式中新增設定,請新增套件參考📦 Microsoft.Extensions.Configuration。 此套件是 .NET 應用程式中設定的基礎。 它提供 ConfigurationBuilder 和相關類型。

using Microsoft.Extensions.Configuration;

var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>()
    {
        ["SomeKey"] = "SomeValue"
    })
    .Build();

Console.WriteLine(configuration["SomeKey"]);

// Outputs:
//   SomeValue

上述程式代碼:

  • 建立新的 ConfigurationBuilder 實例。
  • 將索引鍵/值組的記憶體內部集合新增至組態產生器。
  • 呼叫 Build() 方法來建立 IConfiguration 實例。
  • SomeKey 鍵的值寫入控制台。

雖然此範例使用記憶體內設定,但有許多設定提供者可用,提供檔案導向、環境變數、命令列參數及其他組態來源的功能。 如需詳細資訊,請參閱 .NET 中的組態提供者。

替代託管方法

通常,您的應用程式不僅僅是用來讀取設定。 他們可能會使用相依性注入、日誌記錄和其他服務。 針對使用這些服務的應用程式,建議使用 .NET 泛型主機 方法。 相反地,考慮 新增一個套件參考📦 Microsoft.Extensions.Hosting。 修改 Program.cs 檔案,以符合下列程序代碼:

using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Application code should start here.

await host.RunAsync();

Host.CreateApplicationBuilder(String[]) 方法會依下列順序提供應用程式的預設組態,從最高優先順序到最低優先順序:

  1. 使用 命令列組態提供者的命令列引數。
  2. 使用環境變數組態提供者 的環境變數
  3. 應用程式秘密 當應用程式在 Development 環境中執行時。
  4. appsettings.Environment.json 使用 JSON 設定提供者。 例如,appsettingsProductionjsonappsettingsDevelopmentjson
  5. appsettings.json 使用 JSON 組態提供者
  6. ChainedConfigurationProvider:將現有的 IConfiguration 新增為來源。

新增設定提供程式會覆寫先前的組態值。 例如,命令列組態提供者 會覆寫其他提供者的所有值,因為它是最後添加的。 如果在 SomeKey 和環境中設定 ,則會使用環境值,因為已在 appsettings.json之後新增它。

捆綁

使用 .NET 配置抽象的一大優勢是能夠將設定值 綁定 到 .NET 物件的實例。 例如,JSON 組態提供者可用來將 appsettings.json 檔案對應至 .NET 物件,並與 相依性插入搭配使用。 這可讓 選項設計模式,並且此模式使用類別來提供強型別存取,允許存取相關的設定群組。 默認系結器是基於反射的,但還有一個易於啟用的 來源產生器替代方案

.NET 組態提供各種抽象概念。 請考慮下列介面:

這些抽象概念與其基礎組態提供者無關(IConfigurationProvider)。 換句話說,您可以使用 IConfiguration 實例,從多個提供者存取任何組態值。

系結器可以使用不同的方法來處理組態值:

  • 基本型別的直接反序列化,使用內建轉換器。
  • 當類型存在一個複雜型別時,其複雜型別的 TypeConverter
  • 具有屬性之複雜類型的反映。

注意

系結器有一些限制:

  • 如果屬性具有 private 設定器,或其類型無法轉換,則會忽略該屬性。
  • 忽略沒有對應組態索引鍵的屬性。

系結階層

組態值可以包含階層式數據。 階層式物件會使用組態索引鍵中的 : 分隔符來表示。 若要存取組態值,請使用 : 字元來分隔階層。 例如,請考慮下列組態值:

{
  "Parent": {
    "FavoriteNumber": 7,
    "Child": {
      "Name": "Example",
      "GrandChild": {
        "Age": 3
      }
    }
  }
}

下表代表上述範例 JSON 的範例索引鍵及其對應的值:

鑰匙 價值
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

進階綁定情境

配置綁定器在處理特定類型時有特定的行為與限制。 本節包含下列子區段:

綁定到字典

當您將設定綁定到值為可變集合類型(例如陣列或清單)時,重複綁定到相同的鍵會擴展集合中的值,而不是替換它們。

下列範例示範此行為:

IConfiguration config = new ConfigurationBuilder()
    .AddInMemoryCollection()
    .Build();

config["Queue:0"] = "Value1";
var dict = new Dictionary<string, string[]>() { { "Queue", new[] { "InitialValue" } } };

Console.WriteLine("=== Dictionary Binding with Collection Values ===");
Console.WriteLine($"Initially: {string.Join(", ", dict["Queue"])}");

// In .NET 7+, binding extends the collection instead of replacing it.
config.Bind(dict);
Console.WriteLine($"After Bind: {string.Join(", ", dict["Queue"])}");

config["Queue:1"] = "Value2";
config.Bind(dict);
Console.WriteLine($"After 2nd Bind: {string.Join(", ", dict["Queue"])}");

更多資訊請參見 「綁定設定到字典擴充值」。

帶有冒號的字典鍵

冒號(:)字元保留為組態鍵中的階層分隔符。 這表示你在綁定設定時不能在字典鍵中使用冒號。 如果你的金鑰包含冒號(例如 URL 或其他格式化識別碼),設定系統會將它們解讀為階層路徑,而非字元。 請考慮以下的變通方法:

  • 在配置鍵中使用替代的分隔字元(例如雙重底線 __),必要時用程式化轉換。
  • 手動使用 System.Text.Json 或類似函式庫,將設定解序列化為原始 JSON,這些函式庫支援鍵中使用冒號。
  • 建立一個自訂的映射圖層,將安全金鑰轉換成你想要的金鑰,並加冒號。

綁定 IReadOnly* 類型

設定綁定器不支援直接綁定到 IReadOnlyList<T>IReadOnlyDictionary<TKey, TValue>,或其他唯讀的集合介面。 這些介面缺乏绑定器所需的機制來填充集合。

若要處理唯讀集合,請使用可變型別來設定裝訂器會填充的屬性,然後將這些屬性以唯讀介面的形式公開給消費者:

Console.WriteLine("=== IReadOnly* Types (NOT Directly Supported) ===");

var readonlyConfig = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["Settings:Values:0"] = "Item1",
        ["Settings:Values:1"] = "Item2",
        ["Settings:Values:2"] = "Item3",
    })
    .Build();

// This class uses List<string> for binding, exposes as IReadOnlyList<string>.
var settings = new SettingsWithReadOnly();
readonlyConfig.GetSection("Settings").Bind(settings);

Console.WriteLine("Values bound to mutable List, exposed as IReadOnlyList:");
foreach (var value in settings.ValuesReadOnly)
{
    Console.WriteLine($"  {value}");
}

組態類別實作:

class SettingsWithReadOnly
{
    // Use mutable type for binding
    public List<string> Values { get; set; } = [];

    // Expose as read-only for consumers
    public IReadOnlyList<string> ValuesReadOnly => Values;
}

此方法允許綁定器在透過IReadOnlyList<string>向消費者呈現不可變介面的同時,填充可變List<string>物件。

與參數化建構子綁定

從 .NET 7 開始,配置繫結器支援綁定到具有單一公開參數化建構子的型別。 這使得不可變型別與紀錄能直接從設定中填充:

Console.WriteLine("=== Parameterized Constructor Binding ===");

var ctorConfig = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["AppSettings:Name"] = "MyApp",
        ["AppSettings:MaxConnections"] = "100",
        ["AppSettings:Timeout"] = "30"
    })
    .Build();

// Binding to a type with a single parameterized constructor
var appSettings = ctorConfig.GetSection("AppSettings").Get<AppSettings>();
if (appSettings != null)
{
    Console.WriteLine($"Name: {appSettings.Name}");
    Console.WriteLine($"MaxConnections: {appSettings.MaxConnections}");
    Console.WriteLine($"Timeout: {appSettings.Timeout}");
}

不變設定類別:

// Immutable type with single parameterized constructor.
class AppSettings
{
    public string Name { get; }
    public int MaxConnections { get; }
    public int Timeout { get; }

    public AppSettings(string name, int maxConnections, int timeout)
    {
        Name = name;
        MaxConnections = maxConnections;
        Timeout = timeout;
    }
}

這很重要

該綁定器僅支援具有單一公開參數化建構子的型別。 如果一個型別有多個公開參數化建構子,綁定器無法決定使用哪一個,綁定將失敗。 使用單一參數化建構子或無參數建構器,並使用屬性設定器。

基本範例

若要以基本形式存取組態值,如果沒有 一般主機 方法的協助,請直接使用 ConfigurationBuilder 類型。

提示

System.Configuration.ConfigurationBuilder 類型與 Microsoft.Extensions.Configuration.ConfigurationBuilder 類型不同。 此內容全都專屬於 Microsoft.Extensions.* NuGet 套件和命名空間。

請考慮下列 C# 專案:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.3" />
  </ItemGroup>

</Project>

前面的專案檔參考了數個 NuGet 組態套件:

請考慮範例 appsettings.json 檔案:

{
    "Settings": {
        "KeyOne": 1,
        "KeyTwo": true,
        "KeyThree": {
            "Message": "Oh, that's nice...",
            "SupportedVersions": {
                "v1": "1.0.0",
                "v3": "3.0.7"
            }
        },
        "IPAddressRange": [
            "46.36.198.121",
            "46.36.198.122",
            "46.36.198.123",
            "46.36.198.124",
            "46.36.198.125"
        ]
    }
}

現在,假設此 JSON 檔案,以下是直接使用組態產生器的範例取用模式:

using Microsoft.Extensions.Configuration;

// Build a config object, using env vars and JSON providers.
IConfigurationRoot config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddEnvironmentVariables()
    .Build();

// Get values from the config given their key and their target type.
Settings? settings = config.GetRequiredSection("Settings").Get<Settings>();

// Write the values to the console.
Console.WriteLine($"KeyOne = {settings?.KeyOne}");
Console.WriteLine($"KeyTwo = {settings?.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings?.KeyThree?.Message}");

// Application code which might rely on the config could start here.

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Oh, that's nice...

上述 C# 程式代碼:

  • 創建一個 ConfigurationBuilder
  • 添加 "appsettings.json" 檔案以供 JSON 組態提供者辨識。
  • 將環境變數新增以供環境變數組態提供者辨識。
  • 使用 "Settings" 實例,取得所需的 Settings 區段和相應的 config 實例。

Settings 物件的形狀如下:

public sealed class Settings
{
    public required int KeyOne { get; set; }
    public required bool KeyTwo { get; set; }
    public required NestedSettings KeyThree { get; set; } = null!;
}
public sealed class NestedSettings
{
    public required string Message { get; set; } = null!;
}

主機託管的基本範例

若要存取 IConfiguration 值,您可以再次依賴 Microsoft.Extensions.Hosting NuGet 套件。 建立新的主控台應用程式,並將下列專案檔內容貼到其中:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.3" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
  </ItemGroup>

</Project>

上述項目檔會定義:

  • 應用程式是可執行檔。
  • 編譯專案時,appsettings.json 檔案會複製到輸出目錄。
  • 已新增 Microsoft.Extensions.Hosting NuGet 套件參考。

使用下列內容,在專案的根目錄中新增 appsettings.json 檔案:

{
    "KeyOne": 1,
    "KeyTwo": true,
    "KeyThree": {
        "Message": "Thanks for checking this out!"
    }
}

使用下列 C# 程式代碼取代 Program.cs 檔案的內容:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
int keyOneValue = config.GetValue<int>("KeyOne");
bool keyTwoValue = config.GetValue<bool>("KeyTwo");
string? keyThreeNestedValue = config.GetValue<string>("KeyThree:Message");

// Write the values to the console.
Console.WriteLine($"KeyOne = {keyOneValue}");
Console.WriteLine($"KeyTwo = {keyTwoValue}");
Console.WriteLine($"KeyThree:Message = {keyThreeNestedValue}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Thanks for checking this out!

當您執行此應用程式時,Host.CreateApplicationBuilder 會定義探索 JSON 組態的行為,並透過 IConfiguration 實例公開。 從 host 實例中,您可以向服務提供者詢問 IConfiguration 實例,然後詢問它的值。

提示

以這種方式使用原始 IConfiguration 實例,雖然方便,但擴展性不好。 當應用程式變得複雜度增加,且其對應的組態變得更複雜時,建議您使用 選項模式 作為替代方案。

裝載和使用索引器 API 的基本範例

請考慮上述範例中的相同 appsettings.json 檔案內容:

{
    "SupportedVersions": {
        "v1": "1.0.0",
        "v3": "3.0.7"
    },
    "IPAddressRange": [
        "46.36.198.123",
        "46.36.198.124",
        "46.36.198.125"
    ]
}

使用下列 C# 程式代碼取代 Program.cs 檔案的內容:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateApplicationBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
string? ipOne = config["IPAddressRange:0"];
string? ipTwo = config["IPAddressRange:1"];
string? ipThree = config["IPAddressRange:2"];
string? versionOne = config["SupportedVersions:v1"];
string? versionThree = config["SupportedVersions:v3"];

// Write the values to the console.
Console.WriteLine($"IPAddressRange:0 = {ipOne}");
Console.WriteLine($"IPAddressRange:1 = {ipTwo}");
Console.WriteLine($"IPAddressRange:2 = {ipThree}");
Console.WriteLine($"SupportedVersions:v1 = {versionOne}");
Console.WriteLine($"SupportedVersions:v3 = {versionThree}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//     IPAddressRange:0 = 46.36.198.123
//     IPAddressRange:1 = 46.36.198.124
//     IPAddressRange:2 = 46.36.198.125
//     SupportedVersions:v1 = 1.0.0
//     SupportedVersions:v3 = 3.0.7

這些值是使用索引器 API 來存取,其中每個索引鍵都是字串,而值則是字串。 組態支援屬性、物件、陣列和字典。

設定提供者

下表顯示 .NET Core 應用程式可用的組態提供者。

設定提供者 提供來自[來源]的組態
Azure 應用程式組態 Azure 應用程式組態
Azure 密鑰保管庫 Azure Key Vault
命令列 命令行參數
自定義 自訂來源
環境變數 環境變數
File JSON、XML 和 INI 檔案
每個檔案的鍵 目錄檔案
記憶體 內存集合
應用程式秘密(秘密管理器) 使用者配置檔目錄中的檔案

提示

新增組態提供者的順序很重要。 使用多個組態提供者,且多個提供者指定相同的索引鍵時,會使用最後一個新增的密鑰。

如需各種組態提供者的詳細資訊,請參閱 .NET 中的組態提供者。

另請參閱