Configuração em .NET

A configuração no .NET é realizada usando um ou mais provedores de configuração. Os provedores de configuração leem os dados de configuração de pares chave-valor usando várias de fontes de configuração:

  • Arquivos de configurações, como appsettings.json
  • Variáveis de ambiente
  • Azure Key Vault
  • Configuração de Aplicativos do Azure
  • Argumentos de linha de comando
  • Provedores personalizados, instalados ou criados
  • Arquivos de diretório
  • Objetos do .NET na memória
  • Provedores de terceiros

Observação

Para obter informações sobre como configurar o próprio runtime do .NET, confira Configurações do .NET Runtime.

Conceitos e abstrações

Considerando uma ou mais fontes de configuração, o tipo IConfiguration fornece uma exibição unificada dos dados de configuração. A configuração é somente leitura e o padrão de configuração não foi projetado para ser programaticamente gravável. A interface IConfiguration é uma representação única de todas as fontes de configuração, conforme mostrado no diagrama a seguir:

The `IConfiguration` interface is a single representation of all the configuration sources.

Configurar aplicativos de console

Os aplicativos de console do .NET criados usando o novo modelo de comando dotnet ou o Visual Studio por padrão não expõem as funcionalidades de configuração. Para adicionar a configuração em um novo aplicativo de console .NET, adicione uma referência de pacote ao Microsoft.Extensions.Configuration. Este pacote é a base para a configuração em aplicativos .NET. Ele fornece o ConfigurationBuilder e os tipos relacionados.

using Microsoft.Extensions.Configuration;

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

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

// Outputs:
//   SomeValue

O código anterior:

  • Cria uma nova instância ConfigurationBuilder.
  • Adiciona uma coleção na memória de pares chave-valor ao construtor de configuração.
  • Chama o método Build() para criar uma instância de IConfiguration.
  • Grava o valor da chave SomeKey no console.

Embora este exemplo use uma configuração na memória, há muitos provedores de configuração disponíveis, expondo a funcionalidade para fontes de configuração baseadas em arquivo, em variáveis de ambiente, argumentos de linha de comando e outras. Para obter mais informações, confira Provedores de configuração no .NET.

Abordagem de hospedagem alternativa

Normalmente, seus aplicativos farão mais do que apenas ler a configuração. Eles provavelmente usarão injeção de dependência, registro em log e outros serviços. A abordagem de Host genérico do .NET é recomendada para aplicativos que usam esses serviços. Em vez disso, considere adicionar uma referência de pacote a Microsoft.Extensions.Hosting. Modifique o arquivo Program.cs para corresponder ao seguinte código:

using Microsoft.Extensions.Hosting;

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

// Application code should start here.

await host.RunAsync();

O método Host.CreateApplicationBuilder(String[]) inicializado fornece a configuração padrão para o aplicativo na seguinte ordem, da prioridade mais alta para a mais baixa:

  1. Argumentos de linha de comando usando o Provedor de configuração de linha de comando.
  2. Variáveis de ambiente usando o Provedor de configuração de variáveis de ambiente.
  3. Segredos do aplicativo quando o aplicativo é executado no ambiente Development.
  4. appsettings.json usando o provedor de configuração JSON .
  5. appsettings.Environment.json usando o provedor de configuração JSON. Por exemplo, appsettings.Production.json e appsettings.Development.json.
  6. ChainedConfigurationProvider: adiciona um IConfiguration existente como fonte.

A adição de um provedor de configuração substitui os valores de configuração anteriores. Por exemplo, o provedor de configuração de linha de comando substitui todos os valores de outros provedores porque ele foi adicionado por último. Se SomeKey for definido em appsettings.json e no ambiente, o valor do ambiente será usado porque foi adicionado após appsettings.json.

Associação

Uma das principais vantagens de usar as abstrações de configuração do .NET é a capacidade de associar valores de configuração a instâncias de objetos .NET. Por exemplo, o provedor de configuração JSON pode ser usado para mapear arquivos appsettings.json para objetos .NET e é usado com injeção de dependência. Isso permite o padrão de opções, que usa classes para fornecer acesso fortemente tipado a grupos de configurações relacionadas. A configuração do .NET fornece várias abstrações. Considere as seguintes interfaces:

  • IConfiguration: Representa um conjunto de propriedades de configuração de aplicativo de chave/valor.
  • IConfigurationRoot: representa a raiz de uma hierarquia de IConfiguration.
  • IConfigurationSection: Representa uma seção dos valores de configuração do aplicativo.

Essas abstrações são independentes do provedor de configuração subjacente (IConfigurationProvider). Em outras palavras, você pode usar uma instância IConfiguration para acessar qualquer valor de configuração de vários provedores.

O associador pode usar diferentes abordagens para processar valores de configuração:

  • Desserialização direta (usando conversores internos) para tipos primitivos.
  • O TypeConverter para um tipo complexo quando o tipo tem um.
  • Reflexão para um tipo complexo que tem propriedades.

Observação

O associador tem algumas limitações:

  • As propriedades serão ignoradas se tiverem setters privados ou seu tipo não puder ser convertido.
  • As propriedades sem chaves de configuração correspondentes são ignoradas.

Associando hierarquias

Os valores de configuração podem conter dados hierárquicos. Objetos hierárquicos são representados com o uso do delimitador : nas chaves de configuração. Para acessar um valor de configuração, use o caractere : para delimitar uma hierarquia. Por exemplo, considere os seguintes valores de configuração:

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

A tabela a seguir representa as chaves de exemplo e seus valores correspondentes para o exemplo anterior JSON:

Chave Valor
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Exemplo básico

Para acessar valores de configuração em sua forma básica, sem a assistência da abordagem de host genérico, use o tipo ConfigurationBuilder diretamente.

Dica

O tipo é System.Configuration.ConfigurationBuilder diferente do tipo Microsoft.Extensions.Configuration.ConfigurationBuilder. Todo esse conteúdo é específico para os pacotes e namespaces Microsoft.Extensions.* do NuGet.

Considere o seguinte projeto C#:

<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="8.0.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
  </ItemGroup>

</Project>

O arquivo de projeto anterior faz referência a vários pacotes NuGet de configuração:

Considere um exemplo de arquivo 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"
        ]
    }
}

Agora, devido a esse arquivo JSON, aqui está um padrão de consumo de exemplo usando o construtor de configuração diretamente:

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

O código anterior do C#:

  • Instancia um ConfigurationBuilder.
  • Adiciona o arquivo "appsettings.json" a ser reconhecido pelo provedor de configuração JSON.
  • Adiciona variáveis de ambiente como sendo reconhecidas pelo provedor de configuração de Variável de Ambiente.
  • Obtém a seção "Settings" necessária e a instância correspondente Settings usando a instância config.

O objeto Settings é moldado da seguinte maneira:

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

Exemplo básico com hospedagem

Para acessar o valor IConfiguration, você pode confiar novamente no pacote NuGet Microsoft.Extensions.Hosting. Crie um novo aplicativo de console e cole o seguinte conteúdo de arquivo de projeto nele:

<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.Hosting" Version="8.0.0" />
  </ItemGroup>

</Project>

O arquivo de projeto anterior define que:

  • O aplicativo é um executável.
  • Um arquivo appsettings.json deve ser copiado para o diretório de saída quando o projeto for compilado.
  • A referência do pacote NuGet Microsoft.Extensions.Hosting é adicionada.

Adicione o arquivo appsettings.json na raiz do projeto com o seguinte conteúdo:

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

Substitua o conteúdo do arquivo Program.cs pelo código C# a seguir:

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 você executa esse aplicativo, o Host.CreateApplicationBuilder define o comportamento para descobrir a configuração JSON e expô-la por meio da instância IConfiguration. Na instância host, você pode solicitar o provedor de serviços para a instância IConfiguration e, em seguida, solicitar valores.

Dica

Usar a instância bruta IConfiguration dessa maneira, embora conveniente, não dimensiona muito bem. Quando os aplicativos crescem em complexidade e suas configurações correspondentes se tornam mais complexas, recomendamos que você use o padrão de opções como alternativa.

Exemplo básico com hospedagem e uso da API do indexador

Considere o mesmo conteúdo do arquivo appsettings.json do exemplo anterior:

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

Substitua o conteúdo do arquivo Program.cs pelo código C# a seguir:

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

Os valores são acessados usando a API do indexador em que cada chave é uma cadeia de caracteres e o valor é uma cadeia de caracteres. A configuração dá suporte a propriedades, objetos, matrizes e dicionários.

Provedores de configuração

A tabela a seguir mostra os provedores de configuração disponíveis para aplicativos .NET Core.

Provedor Fornece a configuração de
Provedor de configuração do Aplicativo do Azure Configuração de Aplicativo do Azure
Provedor de configuração do Azure Key Vault Cofre de Chave do Azure
Provedor de configuração de linha de comando Parâmetros de linha de comando
Provedor de Configuração personalizado Fonte personalizada
Provedor de configuração de variáveis de ambiente Variáveis de ambiente
Provedor de configuração de arquivo Arquivos JSON, XML e INI
Provedor de configuração de chave por arquivo Arquivos de diretório
Provedor de configuração de memória Coleções na memória
Segredos do aplicativo (Gerenciador de Segredos) Arquivo no diretório de perfil do usuário

Dica

A ordem na qual os provedores de configuração são adicionados é importante. Quando vários provedores de configuração são usados e mais de um provedor especifica a mesma chave, a última adicionada é usada.

Para obter mais informações sobre vários provedores de configuração, confira Provedores de configuração no .NET.

Confira também