Condividi tramite


Configurazione in .NET

La configurazione in .NET viene eseguita usando uno o più provider di configurazione . I provider di configurazione leggono i dati di configurazione da coppie chiave-valore usando varie origini di configurazione:

  • File di impostazioni, ad esempio appsettings.json
  • Variabili di ambiente
  • Azure Key Vault
  • Configurazione App di Azure
  • Argomenti della riga di comando
  • Provider personalizzati, installati o creati
  • File della directory
  • Oggetti .NET in memoria
  • Fornitori di terze parti

Nota

Per informazioni sulla configurazione del runtime .NET stesso, vedere impostazioni di configurazione del runtime .NET.

Concetti e astrazioni

Data una o più origini di configurazione, il tipo IConfiguration fornisce una visualizzazione unificata dei dati di configurazione. La configurazione è di sola lettura e il modello di configurazione non è progettato per essere scrivibile a livello di codice. L'interfaccia IConfiguration è una singola rappresentazione di tutte le origini di configurazione, come illustrato nel diagramma seguente:

L'interfaccia 'IConfiguration' è una singola rappresentazione di tutte le origini di configurazione.

Configurare le applicazioni console

Le applicazioni console .NET create usando il modello di comando dotnet new o Visual Studio per impostazione predefinita non espongono le funzionalità di configurazione. Per aggiungere la configurazione di una nuova applicazione console .NET, aggiungere un riferimento al pacchetto a Microsoft.Extensions.Configuration. Questo pacchetto è la base per la configurazione nelle app .NET. Fornisce il ConfigurationBuilder e i tipi correlati.

using Microsoft.Extensions.Configuration;

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

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

// Outputs:
//   SomeValue

Il codice precedente:

  • Crea una nuova istanza di ConfigurationBuilder.
  • Aggiunge una raccolta in memoria di coppie chiave-valore al generatore di configurazione.
  • Chiama il metodo Build() per creare un'istanza di IConfiguration.
  • Scrive il valore della chiave SomeKey nella console.

Anche se in questo esempio viene usata una configurazione in memoria, sono disponibili molti provider di configurazione, che espongono funzionalità per le variabili di ambiente, gli argomenti della riga di comando e altre origini di configurazione basate su file. Per ulteriori informazioni, vedere i provider di configurazione in .NET.

Approccio alternativo all'hosting

In genere, le app eseguiranno più operazioni di sola lettura della configurazione. Probabilmente useranno il dependency injection, il logging e altri servizi. L'approccio host generico .NET è consigliato per le app che usano questi servizi. Prendere invece in considerazione l'aggiunta di un riferimento al pacchetto a Microsoft.Extensions.Hosting. Modificare il file Program.cs in modo che corrisponda al codice seguente:

using Microsoft.Extensions.Hosting;

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

// Application code should start here.

await host.RunAsync();

Il metodo Host.CreateApplicationBuilder(String[]) fornisce la configurazione predefinita per l'app nell'ordine seguente, dalla priorità più alta alla più bassa:

  1. Argomenti della riga di comando che usano il provider di configurazione della riga di comando .
  2. Variabili di ambiente che usano il provider di configurazione delle variabili di ambiente .
  3. I segreti dell'app quando l'app viene eseguita nell'ambiente Development.
  4. appsettings.json usando il provider di configurazione JSON .
  5. appsettings.Environment.json utilizzando il provider di configurazione JSON . Ad esempio, appsettings.Produzione.json e appsettings.Sviluppo.json.
  6. ChainedConfigurationProvider : aggiunge come origine un IConfiguration esistente.

L'aggiunta di un provider di configurazione sostituisce i valori di configurazione precedenti. Ad esempio, il provider di configurazione della riga di comando sovrascrive tutti i valori provenienti da altri provider perché è stato aggiunto per ultimo. Se SomeKey è impostato sia in appsettings.json che nell'ambiente, il valore dell'ambiente viene usato perché è stato aggiunto dopo appsettings.json.

Vincolo

Uno dei vantaggi principali dell'uso delle astrazioni di configurazione .NET è la possibilità di associare valori di configurazione a istanze di oggetti .NET. Ad esempio, il provider di configurazione JSON può essere usato per eseguire il mapping dei file appsettings.json agli oggetti .NET e viene usato con l'inserimento delle dipendenze. Questo abilita il modello di opzioni , che usa le classi per fornire l'accesso fortemente tipizzato ai gruppi di impostazioni correlate. Il binder predefinito è basato sulla riflessione, ma c'è un'alternativa: il generatore di origine , facile da abilitare.

La configurazione di .NET fornisce diverse astrazioni. Si considerino le interfacce seguenti:

  • IConfiguration: rappresenta un set di proprietà di configurazione dell'applicazione chiave/valore.
  • IConfigurationRoot: rappresenta la radice di una gerarchia di IConfiguration.
  • IConfigurationSection: rappresenta una sezione dei valori di configurazione dell'applicazione.

Queste astrazioni sono indipendenti dal provider di configurazione sottostante (IConfigurationProvider). In altre parole, è possibile usare un'istanza di IConfiguration per accedere a qualsiasi valore di configurazione da più provider.

Il binder può usare approcci diversi per gestire i valori di configurazione.

  • Deserializzazione diretta (usando convertitori predefiniti) per i tipi primitivi.
  • Il TypeConverter per un tipo complesso quando il tipo ne ha uno.
  • Reflection per un tipo complesso con proprietà.

Nota

Il binder presenta alcune limitazioni:

  • Le proprietà vengono ignorate se dispongono di setter privati o se il tipo non può essere convertito.
  • Le proprietà senza le chiavi di configurazione corrispondenti vengono ignorate.

Gerarchie di vincolo

I valori di configurazione possono contenere dati gerarchici. Gli oggetti gerarchici vengono rappresentati con l'uso del delimitatore : nelle chiavi di configurazione. Per accedere a un valore di configurazione, usare il carattere : per delimitare una gerarchia. Si considerino ad esempio i valori di configurazione seguenti:

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

La tabella seguente rappresenta le chiavi di esempio e i relativi valori corrispondenti per l'esempio JSON precedente:

Chiave Valore
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Esempio di base

Per accedere ai valori di configurazione nel loro formato di base, senza l'assistenza dell'approccio host generico, utilizzare il tipo ConfigurationBuilder direttamente.

Suggerimento

Il tipo di System.Configuration.ConfigurationBuilder è diverso dal tipo di Microsoft.Extensions.Configuration.ConfigurationBuilder. Tutto questo contenuto è specifico per i pacchetti NuGet e gli spazi dei nomi Microsoft.Extensions.*.

Si consideri il progetto C# seguente:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.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="9.0.4" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.4" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.4" />
  </ItemGroup>

</Project>

Il file di progetto precedente fa riferimento a diversi pacchetti NuGet di configurazione:

Si consideri un esempio di file 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"
        ]
    }
}

Ora, dato questo file JSON, ecco un modello di utilizzo di esempio usando direttamente il generatore di configurazione:

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

Il codice C# precedente:

  • Crea un'istanza di ConfigurationBuilder.
  • Aggiunge il file "appsettings.json" da riconoscere dal provider di configurazione JSON.
  • Aggiunge le variabili di ambiente riconosciute dal provider di configurazione delle variabili di ambiente.
  • Ottiene la sezione "Settings" richiesta e l'istanza di Settings corrispondente utilizzando l'istanza di config.

L'oggetto Settings viene modellato nel modo seguente:

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

Esempio di base con hosting

Per accedere al valore IConfiguration, è possibile fare di nuovo affidamento sul pacchetto NuGet Microsoft.Extensions.Hosting. Creare una nuova applicazione console e incollarvi il contenuto del file di progetto seguente:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.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="9.0.4" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.4" />
  </ItemGroup>

</Project>

Il file di progetto precedente definisce che:

  • L'applicazione è un programma eseguibile.
  • Un file appsettings.json deve essere copiato nella directory di output quando il progetto viene compilato.
  • Viene aggiunto il riferimento al pacchetto NuGet Microsoft.Extensions.Hosting.

Aggiungere il file appsettings.json alla radice del progetto con il contenuto seguente:

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

Sostituire il contenuto del file Program.cs con il codice C# seguente:

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!

Quando si esegue questa applicazione, il Host.CreateApplicationBuilder definisce il comportamento per individuare la configurazione JSON ed esporla tramite l'istanza di IConfiguration. Dall'istanza di host è possibile richiedere al provider di servizi l'istanza di IConfiguration e quindi richiedere i valori.

Suggerimento

L'uso dell'istanza grezza di IConfiguration in questo modo, sebbene conveniente, non si adatta molto bene. Quando le applicazioni aumentano di complessità e le configurazioni corrispondenti diventano più complesse, è consigliabile usare il modello di opzioni in alternativa.

Esempio di base con hosting e uso dell'API dell'indicizzatore

Si consideri lo stesso contenuto del file appsettings.json dell'esempio precedente:

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

Sostituire il contenuto del file Program.cs con il codice C# seguente:

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

È possibile accedere ai valori usando l'API dell'indicizzatore in cui ogni chiave è una stringa e il valore è una stringa. La configurazione supporta proprietà, oggetti, matrici e dizionari.

Provider di configurazione

La tabella seguente illustra i provider di configurazione disponibili per le app .NET Core.

Fornitore Fornisce la configurazione da
provider di configurazione delle app Azure Configurazione app di Azure
provider di configurazione di Azure Key Vault Azure Key Vault (Archivio chiavi di Azure)
provider di configurazione della riga di comando Parametri della riga di comando
Provider di configurazione personalizzato Origine personalizzata
provider di configurazione delle variabili di ambiente Variabili di ambiente
provider della configurazione dei file File JSON, XML e INI
provider di configurazione per file chiave File della directory
Provider di configurazione di memoria Collezioni in memoria
Segreti dell'app (Gestore dei Segreti) File nella directory del profilo utente

Suggerimento

L'ordine in cui vengono aggiunti i provider di configurazione è importante. Quando vengono usati più provider di configurazione e più provider specificano la stessa chiave, viene usata l'ultima aggiunta.

Per ulteriori informazioni sui vari provider di configurazione, consultare Configuration providers in .NET.

Vedere anche