Dela via


Konfiguration i .NET

Konfigurationen i .NET utförs med hjälp av en eller flera konfigurationsprovidrar. Konfigurationsprovidrar läser konfigurationsdata från nyckel/värde-par med hjälp av olika konfigurationskällor:

  • Inställningsfiler, till exempel appsettings.json
  • Miljövariabler
  • Azure Key Vault
  • Azure App Configuration
  • Kommandoradsargument
  • Anpassade leverantörer (installerade eller skapade)
  • Katalogfiler
  • Minnesinterna .NET-objekt
  • Tredjepartsleverantörer

Notera

Information om hur du konfigurerar själva .NET-runtime finns i .NET Runtime-konfigurationsinställningar.

Begrepp och abstraktioner

Med en eller flera konfigurationskällor ger den IConfiguration typen en enhetlig vy över konfigurationsdata. Konfigurationen är skrivskyddad och konfigurationsmönstret är inte utformat för att vara programmatiskt skrivbart. Gränssnittet IConfiguration är en enda representation av alla konfigurationskällor, enligt följande diagram:

Gränssnittet

Konfigurera konsolappar

.NET-konsolappar som skapats med hjälp av den nya kommandomallen dotnet eller Visual Studio exponerar som standard inte konfigurationsfunktioner. Om du vill lägga till konfiguration i ett nytt .NET-konsolprogram lägger du till en paketreferens till 📦 Microsoft.Extensions.Configuration. Det här paketet är grunden för konfigurationen i .NET-appar. Den innehåller ConfigurationBuilder och relaterade typer.

using Microsoft.Extensions.Configuration;

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

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

// Outputs:
//   SomeValue

Föregående kod:

  • Skapar en ny ConfigurationBuilder instans.
  • Lägger till en minnesintern samling av nyckel-värdepar till konfigurationsbyggaren.
  • Anropar metoden Build() för att skapa en IConfiguration-instans.
  • Skriver värdet för SomeKey-nyckeln till konsolen.

I det här exemplet används en minnesintern konfiguration, men det finns många tillgängliga konfigurationsprovidrar som exponerar funktioner för filbaserade, miljövariabler, kommandoradsargument och andra konfigurationskällor. Mer information finns i Configuration Providers i .NET.

Alternativ värdmetod

Vanligtvis gör dina appar mer än att bara läsa konfigurationen. De kommer sannolikt att använda beroendeinmatning, loggning och andra tjänster. Metoden .NET Generic Host rekommenderas för appar som använder dessa tjänster. Överväg i stället att lägga till en paketreferens till 📦 Microsoft.Extensions.Hosting. Ändra Program.cs-filen så att den matchar följande kod:

using Microsoft.Extensions.Hosting;

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

// Application code should start here.

await host.RunAsync();

Metoden Host.CreateApplicationBuilder(String[]) tillhandahåller standardkonfiguration för appen i följande ordning, från högsta till lägsta prioritet:

  1. Kommandoradsargument med hjälp av kommandoradskonfigurationsprovider.
  2. Miljövariabler med konfigurationsprovidern för miljövariabler .
  3. Apphemligheter när appen körs i Development-miljön.
  4. apparinställningar.Environment.json med hjälp av JSON-konfigurationsprovidern. Till exempel appinställningar.Produktion.json och appinställningar.Utveckling.json.
  5. appsettings.json med hjälp av JSON-konfigurationsprovidern.
  6. ChainedConfigurationProvider : Adderar en befintlig IConfiguration som källa.

Om du lägger till en konfigurationsprovider åsidosätts tidigare konfigurationsvärden. Till exempel åsidosätter kommandoradskonfigurationsprovidern alla värden från andra leverantörer eftersom den lades till sist. Om SomeKey anges i både appsettings.json och miljön används miljövärdet eftersom det lades till efter appsettings.json.

Bindande

En av de viktigaste fördelarna med att använda .NET-konfigurationsabstraktioner är möjligheten att binda konfigurationsvärden till instanser av .NET-objekt. JSON-konfigurationsprovidern kan till exempel användas för att mappa appsettings.json filer till .NET-objekt och används med beroendeinmatning. Detta möjliggör alternativmönstret, som använder klasser för att ge starkt typad åtkomst till grupper av relaterade inställningar. Standardbindningen är reflektionsbaserad, men det finns ett alternativ som är enkelt att aktivera.

.NET-konfigurationen innehåller olika abstraktioner. Överväg följande gränssnitt:

Dessa abstraktioner är agnostiska för deras underliggande konfigurationsprovider (IConfigurationProvider). Med andra ord kan du använda en IConfiguration-instans för att komma åt alla konfigurationsvärden från flera leverantörer.

Bindaren kan använda olika metoder för att hantera konfigurationsvärden:

  • Direkt deserialisering (med inbyggda konverterare) för primitiva typer.
  • TypeConverter för en komplex typ när typen har en.
  • Reflektion för en komplex typ som har egenskaper.

Notera

Pärmen har några begränsningar:

  • Egenskaper ignoreras om de har privata setters eller om deras typ inte kan konverteras.
  • Egenskaper utan motsvarande konfigurationsnycklar ignoreras.

Bindningshierarkier

Konfigurationsvärden kan innehålla hierarkiska data. Hierarkiska objekt representeras med hjälp av : avgränsare i konfigurationsnycklarna. Om du vill komma åt ett konfigurationsvärde använder du tecknet : för att avgränsa en hierarki. Tänk till exempel på följande konfigurationsvärden:

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

Följande tabell representerar exempelnycklar och deras motsvarande värden för föregående exempel JSON:

Nyckel Värde
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Avancerade bindningsscenarier

Konfigurationsbindningen har specifika beteenden och begränsningar vid arbete med vissa typer. Det här avsnittet innehåller följande underavsnitt:

Anslut till ordlistor

När du binder konfigurationen till en Dictionary<TKey,TValue> där värdet är en föränderlig samlingstyp (t.ex. matriser eller listor) utökar upprepade bindningar till samma nyckel samlingsvärdena i stället för att ersätta dem.

I följande exempel visas det här beteendet:

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"])}");

Mer information finns i Bindning av konfiguration till ordlista utökar värden.

Ordlistenycklar som innehåller kolon

Kolontecknet (:) är reserverat som en hierarkigränsare i konfigurationsnycklar. Det innebär att du inte kan använda kolon i nycklar i en ordlista när du binder konfigurationen. Om dina nycklar innehåller kolon (till exempel URL:er eller andra formaterade identifierare) tolkar konfigurationssystemet dem som hierarkisökvägar i stället för literaltecken. Överväg följande lösningar:

  • Använd alternativa avgränsartecken (till exempel dubbla understreck ) i konfigurationsnycklarna __och transformera dem programmatiskt om det behövs.
  • Deserialisera konfigurationen manuellt som rå JSON med hjälp av System.Text.Json eller ett liknande bibliotek, som stöder kolon i nycklar.
  • Skapa ett anpassat mappningslager som översätter säkra nycklar till önskade nycklar med kolon.

Bind till IReadOnly*-typer

Konfigurationsbindningen stöder inte bindning direkt till IReadOnlyList<T>, IReadOnlyDictionary<TKey, TValue> eller andra skrivskyddade samlingsgränssnitt. Dessa gränssnitt saknar de mekanismer som bindemedlet behöver för att fylla i samlingarna.

Om du vill arbeta med skrivskyddade samlingar använder du muterbara typer för de egenskaper som bindaren tillhandahåller och exponerar dem sedan som skrivskyddade gränssnitt för användare:

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}");
}

Implementeringen av konfigurationsklassen:

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

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

Med denna metod kan bindaren ändra det dynamiska List<string> och samtidigt presentera ett oföränderligt gränssnitt för användare genom IReadOnlyList<string>.

Binda med parametriserade konstruktorer

Från och med .NET 7 stöder konfigurationsbindaren bindning till typer med en enda offentlig parameteriserad konstruktor. På så sätt kan oföränderliga typer och poster fyllas i direkt från konfigurationen:

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}");
}

Den oföränderliga inställningsklassen:

// 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;
    }
}

Viktigt!

Bindaren stöder endast typer med en enda offentlig parametriserad konstruktor. Om en typ har flera offentliga parametriserade konstruktorer kan bindemedlet inte avgöra vilken som ska användas och bindningen misslyckas. Använd antingen en enskild parameteriserad konstruktor eller en parameterlös konstruktor med egenskapsuppsättningar.

Grundläggande exempel

Om du vill komma åt konfigurationsvärden i deras grundläggande form, utan att använda det generiska värdtillvägagångssättet , använd då direkt ConfigurationBuilder typen.

Tips

Den System.Configuration.ConfigurationBuilder typen skiljer sig från den Microsoft.Extensions.Configuration.ConfigurationBuilder typen. Allt det här innehållet är specifikt för Microsoft.Extensions.* NuGet-paket och namnområden.

Överväg följande C#-projekt:

<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>

Den föregående projektfilen refererar till flera NuGet-konfigurationspaket:

Överväg ett exempel appsettings.json fil:

{
    "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"
        ]
    }
}

Nu, med tanke på den här JSON-filen, här är ett exempel på förbrukningsmönster med hjälp av konfigurationsverktyget direkt:

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...

Föregående C#-kod:

  • Instansierar en ConfigurationBuilder.
  • Lägger till "appsettings.json"-filen som ska identifieras av JSON-konfigurationsprovidern.
  • Lägger till miljövariabler som identifieras av miljövariabelkonfigurationsprovidern.
  • Hämtar det nödvändiga "Settings" avsnittet och motsvarande Settings instans med hjälp av den config instansen.

Det Settings objektet formas på följande sätt:

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!;
}

Grundläggande exempel med värdtjänster

Om du vill komma åt IConfiguration-värdet kan du förlita dig igen på Microsoft.Extensions.Hosting NuGet-paketet. Skapa ett nytt konsolprogram och klistra in följande projektfilinnehåll i det:

<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>

Den föregående projektfilen definierar att:

  • Programmet är en körbar fil.
  • En appsettings.json fil ska kopieras till utdatakatalogen när projektet kompileras.
  • NuGet-paketreferensen Microsoft.Extensions.Hosting läggs till.

Lägg till filen appsettings.json i roten av projektet med följande innehåll:

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

Ersätt innehållet i Program.cs-filen med följande C#-kod:

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!

När du kör det här programmet definierar Host.CreateApplicationBuilder beteendet för att identifiera JSON-konfigurationen och exponera den via IConfiguration-instansen. Från den host instansen kan du be tjänsteleverantören om IConfiguration-instansen och sedan be den om värden.

Tips

Att använda den råa IConfiguration-instansen på det här sättet, även om det är praktiskt, skalas inte särskilt bra. När programmen blir mer komplexa och deras motsvarande konfigurationer blir mer komplexa rekommenderar vi att du använder alternativmönstret som ett alternativ.

Grundläggande exempel med värd och användning av indexerar-API:et

Överväg samma appsettings.json filinnehåll från föregående exempel:

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

Ersätt innehållet i Program.cs-filen med följande C#-kod:

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

Värdena används med indexerarens API där varje nyckel är en sträng och värdet är en sträng. Konfigurationen stöder egenskaper, objekt, matriser och ordlistor.

Konfigurationsleverantörer

I följande tabell visas de konfigurationsprovidrar som är tillgängliga för .NET Core-appar.

Konfigurationsprovider Tillhandahåller konfiguration från
Azure App Configuration Azure App Configuration
Azure Key Vault Azure Key Vault
kommandotolk Kommandoradsparametrar
Skräddarsydd Anpassad källa
Miljövariabler Miljövariabler
Arkiv JSON-, XML- och INI-filer
Key-per-file Katalogfiler
Minne Minnesinterna samlingar
Apphemligheter (hemlighetshanterare) Fil i användarprofilkatalogen

Tips

Det är viktigt i vilken ordning konfigurationsleverantörer läggs till. När flera konfigurationsprovidrar används och mer än en provider anger samma nyckel används den sista som läggs till.

Mer information om olika konfigurationsprovidrar finns i Configuration Providers i .NET.

Se även