Configuración en .NET

La configuración de .NET se realiza mediante uno o varios proveedores de configuración. Los proveedores de configuración leen los datos de configuración de los pares clave-valor usando distintos orígenes de configuración:

  • Archivos de configuración, como appsettings.json
  • Variables de entorno
  • Azure Key Vault
  • Azure App Configuration
  • Argumentos de la línea de comandos
  • Proveedores personalizados (instalados o creados)
  • Archivos de directorio
  • Objetos de .NET en memoria
  • Proveedores de terceros

Nota

Para obtener información sobre cómo configurar el propio entorno de ejecución de .NET, vea Opciones de configuración del entorno de ejecución de .NET.

Conceptos y abstracciones

Dados uno o varios orígenes de configuración, el tipo IConfiguration proporciona una vista unificada de los datos de configuración. La configuración es de solo lectura y el patrón de configuración no está diseñado para que sea grabable mediante programación. La interfaz IConfiguration es una única representación de todos los orígenes de configuración, como se muestra en el siguiente diagrama:

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

Configuración de las aplicaciones de consola

De forma predeterminada, las aplicaciones de consola de .NET creadas mediante el comando dotnet new o Visual Studio no exponen funcionalidades de configuración. Para agregar configuración en una nueva aplicación de consola de .NET, agregue una referencia de paquete a Microsoft.Extensions.Configuration. Este paquete es la base para la configuración en las aplicaciones .NET. Proporciona ConfigurationBuilder y tipos relacionados.

using Microsoft.Extensions.Configuration;

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

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

// Outputs:
//   SomeValue

El código anterior:

  • Crea una nueva instancia de ConfigurationBuilder.
  • Agrega una colección en memoria de pares clave-valor al generador de configuración.
  • Llama al método Build() para crear una instancia de IConfiguration.
  • Escribe el valor de la clave SomeKey a la consola.

Aunque en este ejemplo se usa una configuración en memoria, hay muchos proveedores de configuración disponibles, que exponen la funcionalidad para las variables de entorno basadas en archivos, los argumentos de la línea de comandos y otros orígenes de configuración. Para más información, vea Proveedores de configuración en .NET.

Enfoque de hospedaje alternativo

Normalmente, las aplicaciones harán más que solo leer la configuración. Es probable que usen la inserción de dependencias, el registro y otros servicios. Se recomienda el enfoque de host genérico de .NET para las aplicaciones que usan estos servicios. En su lugar, considere la posibilidad de agregar una referencia de paquete a Microsoft.Extensions.Hosting. Modifique el archivo Program.cs para que coincida con el código siguiente:

using Microsoft.Extensions.Hosting;

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

// Application code should start here.

await host.RunAsync();

El método Host.CreateApplicationBuilder(String[]) proporciona la configuración predeterminada para la aplicación en el orden siguiente, de la prioridad más alta a la más baja:

  1. Argumentos de la línea de comandos con el proveedor de configuración de línea de comandos.
  2. Variables de entorno con el proveedor de configuración de variables de entorno.
  3. Secretos de la aplicación cuando la aplicación se ejecuta en el entorno Development.
  4. appsettings.json con el proveedor de configuración JSON.
  5. appsettings.Environment.json con el proveedor de configuración JSON. Por ejemplo,appsettings.Production.json y appsettings.Development.json.
  6. ChainedConfigurationProvider: agrega un elemento IConfiguration existente como origen.

Agregar un proveedor de configuración invalida los valores de configuración anteriores. Por ejemplo, el proveedor de configuración de línea de comandos invalida todos los valores de otros proveedores porque se agrega el último. Si SomeKey se establece en appsettings.json y en el entorno, se usa el valor de entorno porque se agregó después de appsettings.json.

Enlace

Una de las principales ventajas de usar las abstracciones de configuración de .NET es la capacidad de enlazar valores de configuración a instancias de objetos .NET. Por ejemplo, el proveedor de configuración JSON se puede usar para asignar archivos appsettings.json a objetos .NET y se emplea con la inserción de dependencias. Esto permite el patrón de opciones, que usa clases para proporcionar acceso fuertemente tipado a grupos de configuraciones relacionadas. La configuración de .NET proporciona varias abstracciones. Tenga en cuenta las interfaces siguientes:

  • IConfiguration: representa un conjunto de propiedades de configuración de la aplicación de clave- valor.
  • IConfigurationRoot: representa la raíz de una jerarquía de IConfiguration.
  • IConfigurationSection: representa una sección de valores de configuración de la aplicación.

Estas abstracciones son independientes de su proveedor de configuración subyacente (IConfigurationProvider). En otras palabras, puede usar una instancia de IConfiguration para acceder a cualquier valor de configuración desde varios proveedores.

El enlazador puede usar diferentes enfoques para procesar valores de configuración:

  • Deserialización directa (mediante convertidores integrados) para tipos primitivos.
  • TypeConverter para un tipo complejo cuando el tipo tiene uno.
  • Reflexión para un tipo complejo que tiene propiedades.

Nota

El enlazador tiene algunas limitaciones:

  • Las propiedades se omiten si tienen establecedores privados o su tipo no se puede convertir.
  • Las propiedades sin las claves de configuración correspondientes se omiten.

Jerarquías de enlace

Los valores de configuración pueden contener datos jerárquicos. Los objetos jerárquicos se representan con el uso del delimitador : en las claves de configuración. Para acceder a un valor de configuración, use el carácter : para delimitar una jerarquía. Por ejemplo, imagine que usa el siguiente valor de configuración:

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

En la tabla siguiente se representan claves de ejemplo y sus valores correspondientes para el JSON de ejemplo anterior:

Clave Value
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Ejemplo básico

Para acceder a los valores de configuración en su forma básica, sin la ayuda del enfoque de host genérico, use el tipo ConfigurationBuilder directamente.

Sugerencia

El tipo System.Configuration.ConfigurationBuilder es diferente al tipo Microsoft.Extensions.Configuration.ConfigurationBuilder. Todo este contenido es específico de los paquetes NuGet y los espacios de nombres de Microsoft.Extensions.*.

Considere el siguiente proyecto de 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>

El archivo de proyecto anterior hace referencia a varios paquetes NuGet de configuración:

Considere el archivo de ejemplo 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"
        ]
    }
}

Ahora, dado este archivo JSON, este es un patrón de consumo de ejemplo que usa directamente el generador de configuración:

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

El código de C# anterior:

  • Crea instancias de ConfigurationBuilder.
  • Agrega el archivo "appsettings.json" para que lo reconozca el proveedor de configuración JSON.
  • Agrega variables de entorno como reconocidas por el proveedor de configuración de variables de entorno.
  • Obtiene la sección "Settings" necesaria y la instancia Settings correspondiente mediante la instancia config.

El objeto Settings se modela del modo siguiente:

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

Ejemplo básico con hospedaje

Para acceder al valor IConfiguration, puede confiar de nuevo en el paquete NuGet Microsoft.Extensions.Hosting. Cree una aplicación de consola y pegue en ella el siguiente contenido del archivo de proyecto:

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

El archivo de proyecto anterior define lo siguiente:

  • La aplicación es un archivo ejecutable.
  • Debe copiarse un archivo appsettings.json en el directorio de salida cuando se compile el proyecto.
  • Se agrega una referencia al paquete NuGet Microsoft.Extensions.Hosting.

Agregue el archivo xunit.runner.json a la raíz del proyecto con el siguiente contenido:

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

Reemplace el contenido del archivo Program.cs con el siguiente código de C#:

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!

Al ejecutar esta aplicación, Host.CreateApplicationBuilder define el comportamiento para detectar la configuración JSON y exponerla a través de la instancia de IConfiguration. Desde la instancia de host, puede pedir al proveedor de servicios la instancia de IConfiguration y, luego, solicitarle valores.

Sugerencia

El uso de la instancia de IConfiguration sin procesar de esta manera, aunque es práctico, no permite un buen escalado. Cuando las aplicaciones crezcan en complejidad y sus configuraciones correspondientes se vuelvan más complejas, se recomienda usar el patrón de opciones como alternativa.

Ejemplo básico con hospedaje y uso de la API del indexador

Considere el mismo contenido del archivo appsettings.json del ejemplo anterior:

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

Reemplace el contenido del archivo Program.cs con el siguiente código de C#:

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

Se obtiene acceso a los valores mediante la API del indexador donde cada clave es una cadena y el valor es una cadena. La configuración admite propiedades, objetos, matrices y diccionarios.

Proveedores de configuración

En la siguiente tabla se muestran los proveedores de configuración disponibles para las aplicaciones de .NET Core.

Proveedor Proporciona la configuración de
Proveedor de configuración de aplicaciones de Azure Configuración de aplicaciones de Azure
Proveedor de configuración de Azure Key Vault Azure Key Vault
Proveedor de configuración de línea de comandos Parámetros de la línea de comandos
Proveedor de configuración personalizada Origen personalizado
Proveedor de configuración de variables de entorno Variables de entorno
Proveedor de configuración de archivo Archivos JSON, XML e INI
Proveedor de configuración de clave por archivo Archivos de directorio
Proveedor de configuración de memoria Colecciones en memoria
Secretos de aplicaciones (Administrador de secretos) Archivo en el directorio del perfil de usuario

Sugerencia

El orden en que se agregan proveedores de configuración es importante. Cuando se usan varios proveedores de configuración y más de uno especifica la misma clave, se usa la última agregada.

Para obtener más información sobre los distintos proveedores de configuración, consulte Proveedores de configuración en .NET.

Vea también