No solo appsettings.json — gestión práctica de configuración en aplicaciones de negocio Windows (entornos, secretos y ubicaciones de escritura)

· · CSharp, .NET, appsettings.json, IConfiguration, IOptions, Generic Host, Gestión de configuración, Desarrollo de Windows, Consultoría técnica

«Quiero cambiar la cadena de conexión por entorno», «quiero guardar las preferencias de visualización por usuario», «hemos dejado la clave API en appsettings.json». En una aplicación Windows de negocio cualquiera llega a colocar un appsettings.json y leerlo desde IConfiguration; sin embargo, las decisiones posteriores —ajustes por entorno, ubicación de valores escribibles, secretos y cambios mientras se ejecuta— suelen llegar a producción sin ordenarse bien.

Este artículo recorre, en el orden en que aparecen las decisiones reales, la superposición de IConfiguration y proveedores, configuración por entorno, recepción tipada con el patrón Options, ubicaciones de ajustes escribibles, secretos, los límites reales de modificar ajustes en ejecución y un mapa de migración desde app.config / Settings.settings.

1. La conclusión primero

La gestión de configuración comienza decidiendo la «ubicación» según el «tipo de ajuste».

Tipo de ajuste Ejemplos Primera ubicación recomendada Motivo
Valor predeterminado de aplicación Nivel de registro predeterminado, parámetros UI appsettings.json Valor común no dependiente de entorno, incluido con la compilación
Ajuste por entorno Cadena de conexión o endpoint diferente entre pruebas y producción appsettings.{Environment}.json + variables de entorno Aprovecha el orden de sobrescritura predeterminado
Ajuste por usuario Última carpeta abierta, posición de ventana, preferencias personales Archivo propio bajo %LOCALAPPDATA% o %APPDATA% Se necesita área escribible por usuario
Ajuste por máquina, compartido por usuarios Puerto COM de un equipo, dirección de servidor de licencia Archivo propio bajo %ProgramData% Un administrador configura uno por equipo y se comparte
Secreto Contraseña de cadena de conexión, clave API, token Archivo protegido con DPAPI en producción; user-secrets solo en desarrollo No dejarlo en texto plano; no reutilizar desarrollo en producción
Valor que cambia en ejecución Indicador de función, cambio dinámico de nivel de registro appsettings.json con reloadOnChange + IOptionsMonitor Úselo solo para valores que deben aplicarse sin reiniciar

Las conclusiones que acompañan a la tabla son estas:

  • La prioridad de configuración sigue una única regla: gana el proveedor añadido después. El orden predeterminado es appsettings.jsonappsettings.{Environment}.json → user secrets solo en desarrollo → variables de entorno → argumentos de línea de comandos. Si una clave se repite, prevalece la que se leyó al final. Recordarlo explica la mayoría de «lo escribí en JSON, pero no se aplica».1
  • Con Host.CreateApplicationBuilder no hace falta construir esa jerarquía a mano. Incluso una aplicación de escritorio Windows Forms/WPF obtiene los mismos valores predeterminados usando Generic Host.23
  • El entorno se cambia con DOTNET_ENVIRONMENT o ASPNETCORE_ENVIRONMENT. Con WebApplication, DOTNET_ENVIRONMENT tiene prioridad y, si ninguno existe, el valor predeterminado es Production. En escritorio y servicios Windows hay que diseñar quién y cómo entrega esa variable al proceso.4
  • No reciba los ajustes como DTO suelto: recíbalos tipados con la familia IOptions<T>. Si basta una vez al inicio, use IOptions<T>; si debe reflejar cambios sin reiniciar, IOptionsMonitor<T>. Usar ambos sin entender la diferencia produce tanto valores que cambian cuando no deberían como valores que no cambian cuando deberían.5
  • Haga fallar la configuración al iniciar, no durante la operación. ValidateDataAnnotations() combinado con ValidateOnStart() permite detectar la equivocación como excepción al arrancar y evita descubrirla a medianoche con un NullReferenceException.6
  • No guarde secretos en texto plano dentro de appsettings.json. En desarrollo use user-secrets; en producción, DPAPI (ProtectedData) o el Administrador de credenciales. user-secrets no está cifrado y la documentación lo declara una función solo de desarrollo.78

2. Base del sistema de configuración .NET — IConfiguration y proveedores

El sistema de configuración .NET tiene el aspecto de un único almacén clave-valor, IConfiguration, pero detrás superpone varios proveedores de configuración. JSON, variables de entorno, argumentos de línea de comandos, INI, XML y colecciones en memoria se integran bajo la misma interfaz.9

Los proveedores se superponen con una regla simple: «gana el añadido después». Si la misma clave existe en varios, vale el último proveedor añadido.1

Con Host.CreateApplicationBuilder(args) se compone por defecto el siguiente orden; cuanto mayor es el número, mayor prioridad tiene.2

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. Secret Manager, solo en desarrollo
  4. Variables de entorno
  5. Argumentos de línea de comandos

Este orden es común para consola, Worker Service y Windows Forms. El ejemplo mínimo es:

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

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

// De forma predeterminada, appsettings.json / appsettings.{Environment}.json /
// las variables de entorno y los argumentos de línea de comandos se cargan con el orden de prioridad indicado arriba.
string? connectionString = builder.Configuration.GetConnectionString("Main");

using IHost host = builder.Build();
await host.RunAsync();

Incluso en una aplicación de escritorio como Windows Forms basta añadir Microsoft.Extensions.Hosting para usar el mismo HostApplicationBuilder. Como se explica en Qué es Generic Host, Generic Host centraliza configuración, DI y registro; ser una aplicación de escritorio no es motivo para renunciar a sus ventajas. Para una composición concreta con trabajo residente, vea Usar Generic Host + BackgroundService en una aplicación de escritorio.

Hay un detalle con variables de entorno: la configuración del host, como raíz de contenido y nombre de entorno, se lee de variables con prefijo DOTNET_, pero eso no se aplica a valores generales de aplicación leídos por IConfiguration. Las variables de aplicación sin prefijo ya se incluyen mediante AddEnvironmentVariables() en el orden predeterminado.10 Para un prefijo propio, añádalo explícitamente:

using Microsoft.Extensions.Configuration;

// Como se agrega después de los proveedores predeterminados, tiene la prioridad más alta.
builder.Configuration.AddEnvironmentVariables(prefix: "MyApp_");

3. Configuración por entorno — appsettings.{Environment}.json

Para cambiar cadena de conexión o endpoint por entorno, use archivos como appsettings.Development.json, appsettings.Staging.json y appsettings.Production.json. Es esencial tratarlos como archivos de diferencias que sobrescriben el appsettings.json base: no hay que repetir todas las claves, solo las que cambian por entorno.1

El nombre del entorno procede de DOTNET_ENVIRONMENT o ASPNETCORE_ENVIRONMENT. Con WebApplication, DOTNET_ENVIRONMENT prevalece; si ninguno se configura, el predeterminado es Production. Windows no distingue mayúsculas de minúsculas en nombres de variables, Linux sí, por lo que conviene normalizar la escritura si se prevén contenedores.4

En una aplicación de escritorio o servicio Windows, el trabajo real es decidir cómo se entrega la variable de entorno. launchSettings.json de ASP.NET Core sirve solo para desarrollo local; en producción hace falta otro mecanismo. Hay tres formas representativas:

  • Configurar una variable de entorno por máquina. Persistir setx DOTNET_ENVIRONMENT Production /M hace que se herede por los procesos de ese equipo, pero no sirve bien si se alojan aplicaciones de varios entornos en la misma máquina.
  • Entregar la variable al proceso de inicio de un servicio Windows. Un servicio se inicia en contexto distinto a la sesión de usuario interactivo y no hereda las variables del usuario. Para detalles de cuenta y separación de sesión, consulte Cómo crear y operar servicios Windows. Una variable de máquina o un wrapper por lotes ligero que haga SET antes de iniciar el ejecutable son opciones realistas.
  • Si se inicia mediante Programador de tareas, usar argumentos de línea de comandos es más fiable. La interfaz no permite establecer directamente una variable de entorno en «Acción»; pasar --environment Production y leerlo con AddCommandLine(args) reduce errores. Las particularidades de cuenta de ejecución y tipo de inicio de sesión están en Cuando una tarea del Programador no se ejecuta o termina con 0x1.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

var options = new HostApplicationBuilderSettings
{
    Args = args,
    // Para rutas de ejecución (como el Programador de tareas) donde no se proporcionan
    // variables de entorno, también se permite cambiar de entorno mediante argumentos de línea de comandos.
};
HostApplicationBuilder builder = Host.CreateApplicationBuilder(options);

Console.WriteLine($"Entorno actual: {builder.Environment.EnvironmentName}");

4. Patrón Options — recibir configuración como tipos

Leer con una clave de texto como IConfiguration["Key:SubKey"] no detecta erratas y se vuelve difícil de seguir al aumentar la anidación. En la práctica, lo básico es el patrón Options, que liga la configuración a un POCO y la recibe tipada.

public sealed class ExternalApiOptions
{
    public const string SectionName = "ExternalApi";

    public required string BaseUrl { get; set; }
    public required string ApiKey { get; set; }
    public int TimeoutSeconds { get; set; } = 30;
}

El registro y binding se escriben así:

using Microsoft.Extensions.DependencyInjection;

builder.Services
    .AddOptions<ExternalApiOptions>()
    .Bind(builder.Configuration.GetSection(ExternalApiOptions.SectionName));

Las tres interfaces tienen naturalezas distintas.5

Interfaz Vida del registro Reflejo de cambios Uso principal
IOptions<T> Singleton No; se calcula una vez al arrancar Ajustes que se suponen inmutables; el más simple
IOptionsSnapshot<T> Scope Se recalcula cuando se reconstruye el scope Contextos con scope claro, como solicitud web
IOptionsMonitor<T> Singleton Devuelve el valor actual y notifica con OnChange Servicios residentes que deben detectar cambios en el momento

En aplicaciones de escritorio y servicios Windows sin scope de solicitud HTTP, IOptionsSnapshot<T> se comporta en la práctica como IOptions<T> salvo que se cree el scope manualmente. Si se quieren detectar cambios, use directamente IOptionsMonitor<T>.

Los valores como BaseUrl, ApiKey y timeout pueden obtenerse desde IOptionsMonitor en cada llamada, pero el HttpClient se obtiene y reutiliza desde IHttpClientFactory. Crear y desechar HttpClient con cada llamada destruye y reconstruye sockets y pool de conexiones y puede agotar puertos efímeros con sondeo o lotes frecuentes.

using Microsoft.Extensions.Options;

public sealed class ExternalApiClient(
    IHttpClientFactory httpClientFactory,
    IOptionsMonitor<ExternalApiOptions> optionsMonitor)
{
    public async Task<string> FetchAsync(CancellationToken cancellationToken)
    {
        // Obtiene el valor más reciente en cada llamada; se refleja si se actualiza el archivo de configuración.
        ExternalApiOptions current = optionsMonitor.CurrentValue;

        // Obtiene HttpClient mediante la factoría y reutiliza el grupo de conexiones interno.
        HttpClient client = httpClientFactory.CreateClient(nameof(ExternalApiClient));

        using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(new Uri(current.BaseUrl), "status"));
        request.Headers.Add("X-Api-Key", current.ApiKey);

        using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(current.TimeoutSeconds));
        using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

        using HttpResponseMessage response = await client.SendAsync(request, linkedCts.Token);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync(cancellationToken);
    }
}

Registre el cliente con nombre mediante builder.Services.AddHttpClient(nameof(ExternalApiClient));. Valores que pueden cambiar, como BaseUrl y ApiKey, se ponen en el HttpRequestMessage en cada petición; la creación y destrucción de la instancia HttpClient queda en la factoría.

Una configuración incorrecta al manifestarse durante ejecución prolonga la investigación. DataAnnotations y ValidateOnStart() permiten que una aplicación con configuración rota no llegue a iniciar.6

using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;

public sealed class ExternalApiOptions
{
    public const string SectionName = "ExternalApi";

    [Required, Url]
    public required string BaseUrl { get; set; }

    [Required, MinLength(16)]
    public required string ApiKey { get; set; }

    [Range(1, 300)]
    public int TimeoutSeconds { get; set; } = 30;
}

builder.Services
    .AddOptions<ExternalApiOptions>()
    .Bind(builder.Configuration.GetSection(ExternalApiOptions.SectionName))
    .ValidateDataAnnotations()
    .ValidateOnStart(); // La validación se ejecuta al iniciar el host (StartAsync/RunAsync), antes de iniciar los servicios del host.

Sin ValidateOnStart(), la validación se retrasa hasta el primer acceso real a la opción. Además, se ejecuta al iniciar el host, StartAsync/RunAsync, no justo después de Build(). Para evitar el fallo intermitente de «la aplicación inició, pero cae al abrir por primera vez la pantalla que usa ese ajuste», use ValidateOnStart() por norma en ajustes de aplicaciones de negocio.6

5. Dónde guardar configuración que se puede escribir

appsettings.json es para valores predeterminados de solo lectura, no para ajustes que la propia aplicación va a reescribir. Muchas aplicaciones se instalan bajo Program Files, donde el usuario estándar no puede escribir; de lo contrario aparece una excepción o, mediante virtualización del sistema de archivos de Windows, contenido distinto por usuario.

Separe los ajustes escribibles por naturaleza. Es seguro partir de las carpetas especiales obtenidas con Environment.GetFolderPath.11

Ubicación Obtención Uso
%LOCALAPPDATA%\empresa\aplicación Environment.SpecialFolder.LocalApplicationData Ajustes y datos predeterminados por usuario
%APPDATA%\empresa\aplicación (Roaming) Environment.SpecialFolder.ApplicationData Solo ajustes que deben seguir al usuario en perfiles móviles
%ProgramData%\empresa\aplicación Environment.SpecialFolder.CommonApplicationData Ajuste por máquina compartido por usuarios; requiere diseño de ACL
using System;
using System.IO;
using System.Text.Json;

public sealed class UserSettingsStore
{
    private readonly string _filePath;

    public UserSettingsStore()
    {
        string root = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        string dir = Path.Combine(root, "KomuraSoft", "MyApp");
        Directory.CreateDirectory(dir);
        _filePath = Path.Combine(dir, "user-settings.json");
    }

    public UserSettings Load()
    {
        if (!File.Exists(_filePath))
        {
            return new UserSettings();
        }
        string json = File.ReadAllText(_filePath);
        return JsonSerializer.Deserialize<UserSettings>(json) ?? new UserSettings();
    }

    public void Save(UserSettings settings)
    {
        string json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
        // El llamador debe serializar las escrituras simultáneas en el mismo proceso.
        File.WriteAllText(_filePath, json);
    }
}

public sealed class UserSettings
{
    public string? LastOpenedFolder { get; set; }
    public int WindowWidth { get; set; } = 1024;
    public int WindowHeight { get; set; } = 768;
}

Mezclar en un solo archivo ajustes por usuario y por máquina provoca que, en equipos compartidos, «el ajuste de A perjudique a B». Para entender usuario/máquina y perfiles Windows, consulte Cómo funcionan los perfiles de usuario de Windows; para una tabla general de elección de ubicación, Cómo elegir dónde guardar datos de una aplicación Windows.

6. Secretos — cadenas de conexión y claves API

Dejar contraseñas de cadenas de conexión o claves API tal cual en appsettings.json es un riesgo práctico aunque esté en .gitignore: puede filtrarse al distribuir por una carpeta compartida, pedir el archivo en soporte o conservarse una configuración antigua en una copia de seguridad.

En desarrollo, use Secret Manager, dotnet user-secrets. Es una herramienta para la experiencia de desarrollo, no cifra los secretos: guarda JSON en texto plano en %APPDATA%\Microsoft\UserSecrets\<UserSecretsId>\secrets.json, y la documentación indica que no debe tratarse como almacén de confianza ni usarse fuera del desarrollo.7

dotnet user-secrets init
dotnet user-secrets set "ExternalApi:ApiKey" "valor-para-desarrollo"

En producción, use DPAPI (Data Protection API) de Windows para cifrar ligado a las credenciales de usuario o de máquina. ProtectedData.Protect / Unprotect son el envoltorio; con DataProtectionScope.CurrentUser se puede descifrar solo con la misma cuenta y máquina. DPAPI es exclusivo de Windows; en otra plataforma produce PlatformNotSupportedException, por lo que debe contemplarse en el diseño.8

using System.Security.Cryptography;
using System.Text;

public static class SecretProtector
{
    // Mezclar una entropía que indique el propósito ayuda a no confundirlo con datos protegidos para otros fines.
    private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("MyApp.ExternalApi.ApiKey");

    public static string Protect(string plainText)
    {
        byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
        byte[] protectedBytes = ProtectedData.Protect(plainBytes, Entropy, DataProtectionScope.CurrentUser);
        return Convert.ToBase64String(protectedBytes);
    }

    public static string Unprotect(string protectedBase64)
    {
        byte[] protectedBytes = Convert.FromBase64String(protectedBase64);
        byte[] plainBytes = ProtectedData.Unprotect(protectedBytes, Entropy, DataProtectionScope.CurrentUser);
        return Encoding.UTF8.GetString(plainBytes);
    }
}

Para detalles de implementación —dónde guardar valores DPAPI, elección de CurrentUser o LocalMachine y trampas de una aplicación usada por varias personas en la misma máquina— vea Almacenamiento de secretos en aplicaciones Windows — evitar configuración en texto plano con DPAPI.

La frontera entre texto plano permitido y secreto es simple: pregúntese si una filtración exige reemitir contraseña o clave API, investigar acceso indebido o notificar a una autoridad. Nombre de host y puerto suelen tener poco impacto; la contraseña o token incluidos son siempre secretos. Construir la cadena separando «información de servidor» y «credenciales» permite proteger con DPAPI solo la segunda parte.

7. Cambio de configuración en ejecución — la realidad de reloadOnChange

La llamada predeterminada a AddJsonFile, incluida internamente por Host.CreateApplicationBuilder, usa reloadOnChange: true; appsettings.json y appsettings.{Environment}.json se recargan al cambiar el archivo. PhysicalFileProvider vigila el cambio con FileSystemWatcher.12

Hay límites prácticos:

  • Solo se reflejan valores leídos mediante IOptionsMonitor<T> y IOptionsSnapshot<T>. IOptions<T> conserva el valor de inicio; el caso «edité el archivo pero no se aplica» suele ser confundirlos.
  • FileSystemWatcher puede no notificar de forma fiable en contenedores Docker o recursos compartidos de red. Con DOTNET_USE_POLLING_FILE_WATCHER=true se cambia a sondeo cada cuatro segundos, intervalo que no puede modificarse.13 Las pérdidas, buffer lleno y eventos duplicados del watcher se tratan en Guía práctica de FileSystemWatcher.
  • Un cambio puede notificar varias veces. Si al detectar cambio se relanza trabajo costoso, aplique debounce a disparos cercanos o compare el hash del contenido y procese solo cambios reales.

No es necesario perseguir siempre «aplicar sin reiniciar». Para valores ligeros como nivel de registro o indicador de función, IOptionsMonitor puede aplicar de inmediato. Para cadena de conexión de base de datos o tamaño de ThreadPool, donde un cambio contradice recursos en uso, suele ser más seguro declarar explícitamente «se aplica al reiniciar». Que operaciones pueda saber qué ajuste se aplica al guardar y cuál exige reinicio importa más que usar o no reloadOnChange.

8. Mapa de migración desde app.config / Settings.settings

Al migrar una aplicación de la época .NET Framework a .NET, también debe rehacerse la configuración.14

.NET Framework .NET Nota
<appSettings> de App.config / Web.config appsettings.json + IConfiguration El anidamiento JSON expresa naturalmente la jerarquía
ConfigurationManager.AppSettings["Key"] builder.Configuration["Key"] o IOptions<T> De acceso por cadena a acceso tipado
ConfigurationManager.ConnectionStrings builder.Configuration.GetConnectionString("Name") Se conserva la convención de sección ConnectionStrings
Settings.settings de ámbito usuario Archivo JSON propio bajo %LOCALAPPDATA% No existe el mecanismo autogenerado de ApplicationSettingsBase; hay que serializar y guardar
Settings.settings de ámbito aplicación appsettings.json Tratar como valor predeterminado de solo lectura
Cifrado de <connectionStrings> con aspnet_regiis, etc. DPAPI (ProtectedData) Cambia el mecanismo de cifrado; hay que rehacerlo al migrar

Hay dos trampas frecuentes. La primera: al añadir el paquete NuGet System.Configuration.ConfigurationManager, el código que lee App.config puede seguir funcionando. Es un paso inicial válido, pero no debe dejarse así: incluya la migración a appsettings.json en el plan. Bibliotecas de alrededor, como proveedores de registro, también se han movido a appsettings.json y queda cada vez menos motivo para mantener el mecanismo anterior solo para leer App.config.14

La segunda son los ajustes de ámbito usuario de Settings.settings. En .NET Framework bastaba Properties.Settings.Default.Save() para guardarlos automáticamente por usuario; .NET no ofrece de serie un mecanismo equivalente. Al migrar debe prepararse una clase de persistencia como la del capítulo 5.

Para el otro lado de la migración —compatibilidad de bibliotecas, COM y método de distribución, además de configuración— consulte Lista de comprobación antes de migrar de .NET Framework a .NET al inicio del proyecto.

Resumen

La gestión de configuración .NET combina la superposición de proveedores mediante IConfiguration, la recepción tipada con la familia IOptions y el cambio de entorno con variables de entorno. Esos tres mecanismos sirven de forma parecida en muchas aplicaciones; los problemas propios de una aplicación Windows de negocio se concentran después: ubicación de ajustes escribibles, protección de secretos, cuánto permitir cambios en ejecución y cómo retirar activos de la era app.config.

Vaya un paso más allá de «todo está en appsettings.json» y separe ubicación y tratamiento por tipo de ajuste. Para una revisión de configuración de una aplicación existente o la estrategia de migración desde app.config, normalmente hace falta ver archivos reales y entorno de despliegue; consulte si tiene dudas.

Artículos relacionados

Ámbitos de consulta relacionados

KomuraSoft LLC atiende consultas técnicas de diseño de gestión de configuración para aplicaciones Windows de negocio, operación de configuración por entorno y estrategia de migración de activos app.config existentes.

Enlaces de referencia

  1. Microsoft Learn, Configuration in .NET - Alternative hosting approach. Sobre el orden de prioridad predeterminado armado por Host.CreateApplicationBuilder.  2 3

  2. Microsoft Learn, .NET Generic Host - Host builder settings. Sobre el orden de configuración de host y de aplicación que lee Host.CreateApplicationBuilder.  2

  3. Microsoft Learn, Use the .NET Generic Host in a Windows Forms app. Sobre incorporar Generic Host, DI, configuración y registro en Windows Forms. 

  4. Microsoft Learn, ASP.NET Core runtime environments. Sobre DOTNET_ENVIRONMENT, ASPNETCORE_ENVIRONMENT, Production y diferencias de mayúsculas entre Windows y Linux.  2

  5. Microsoft Learn, Options pattern in .NET - Options interfaces. Sobre vida y momento de actualización de IOptions, IOptionsSnapshot e IOptionsMonitor.  2

  6. Microsoft Learn, Options pattern in .NET - Options validation. Sobre ValidateDataAnnotations y ValidateOnStart.  2 3

  7. Microsoft Learn, Safe storage of app secrets in development in ASP.NET Core. Sobre el almacenamiento en texto plano de Secret Manager y su uso exclusivo de desarrollo.  2

  8. Microsoft Learn, ProtectedData Class. Sobre DPAPI, Protect/Unprotect, scopes CurrentUser/LocalMachine y exclusividad de Windows.  2

  9. Microsoft Learn, Configuration providers in .NET. Sobre integrar fuentes como JSON, variables, línea de comandos, INI y XML bajo IConfiguration. 

  10. Microsoft Learn, Configuration providers in .NET - Environment variable configuration provider. Sobre variables DOTNET_, configuración de host/aplicación y añadir prefijos personalizados. 

  11. Microsoft Learn, Environment.GetFolderPath Method. Sobre Environment.SpecialFolder y GetFolderPath. 

  12. Microsoft Learn, Detect changes with change tokens in ASP.NET Core. Sobre reloadOnChange y vigilancia con PhysicalFileProvider/FileSystemWatcher. 

  13. Microsoft Learn, Options pattern in .NET - IOptionsMonitor. Sobre las notificaciones de cambios de IOptionsMonitor y el sondeo de cuatro segundos mediante DOTNET_USE_POLLING_FILE_WATCHER. 

  14. Microsoft Learn, Modernize after upgrading to .NET from .NET Framework - App.config. Sobre migrar de App.config a appsettings.json y mantener compatibilidad con System.Configuration.ConfigurationManager.  2

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Puedo dejar appsettings.json en la misma carpeta que el exe?
No hay problema si contiene valores predeterminados de solo lectura. Pero si se instala bajo Program Files, la aplicación no puede diseñarse para reescribir appsettings.json: los usuarios estándar no tienen permiso de escritura y se producirán excepciones en ejecución o contenido distinto por usuario debido a la virtualización de Windows. Separe los ajustes que requieren escritura en otro archivo bajo %LOCALAPPDATA% o %ProgramData%.
¿Debo priorizar variables de entorno o appsettings.json?
La base es no cambiar la prioridad predeterminada y usarla tal como está: appsettings.json → appsettings.{Environment}.json → variables de entorno → argumentos de línea de comandos, donde cada fuente posterior sobrescribe. El criterio cuando hay duda es la naturaleza del valor: valores predeterminados que pueden incluirse en el artefacto de compilación van en appsettings.json; valores que cambian por destino de despliegue o contenedor, en variables de entorno.
¿Cómo debo dividir las clases de configuración?
Divida las clases de opciones por función o responsabilidad. Por ejemplo, ConnectionOptions para cadenas de conexión y ExternalApiOptions para integración con API externa; no amontone ajustes no relacionados en una clase. Al separarlas, la validación y recarga con IOptionsSnapshot/IOptionsMonitor se divide de forma natural y la validación DataAnnotations queda contenida en cada clase.
¿Debo migrar desde archivos INI o el registro?
Si va a rehacer la gestión de configuración, recomendamos unificar en appsettings.json + IConfiguration. .NET también ofrece un proveedor INI, por lo que puede leer el archivo INI existente y migrar gradualmente. El registro no forma parte del alcance estándar de proveedores de configuración .NET; si hay activos existentes que dependen de él, es realista escribir código puente de solo lectura y acercarlos gradualmente a appsettings.json.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog