No solo appsettings.json — gestión práctica de configuración en aplicaciones de negocio Windows (entornos, secretos y ubicaciones de escritura)
· Go Komura · 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.json→appsettings.{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.CreateApplicationBuilderno 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_ENVIRONMENToASPNETCORE_ENVIRONMENT. ConWebApplication,DOTNET_ENVIRONMENTtiene prioridad y, si ninguno existe, el valor predeterminado esProduction. 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, useIOptions<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 conValidateOnStart()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
appsettings.jsonappsettings.{Environment}.json- Secret Manager, solo en desarrollo
- Variables de entorno
- 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 /Mhace 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
SETantes 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 Productiony leerlo conAddCommandLine(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>yIOptionsSnapshot<T>.IOptions<T>conserva el valor de inicio; el caso «edité el archivo pero no se aplica» suele ser confundirlos. FileSystemWatcherpuede no notificar de forma fiable en contenedores Docker o recursos compartidos de red. ConDOTNET_USE_POLLING_FILE_WATCHER=truese 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
- Qué es Generic Host
- Usar Generic Host + BackgroundService en una aplicación de escritorio
- Cuando una tarea del Programador no se ejecuta o termina con 0x1
- Cómo crear y operar servicios Windows
- Cómo elegir dónde guardar datos de una aplicación Windows
- Cómo funcionan los perfiles de usuario de Windows
- Almacenamiento de secretos en aplicaciones Windows — evitar configuración en texto plano con DPAPI
- Guía práctica de FileSystemWatcher
- Lista de comprobación antes de migrar de .NET Framework a .NET
Á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
-
Microsoft Learn, Configuration in .NET - Alternative hosting approach. Sobre el orden de prioridad predeterminado armado por Host.CreateApplicationBuilder. ↩ ↩2 ↩3
-
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
-
Microsoft Learn, Use the .NET Generic Host in a Windows Forms app. Sobre incorporar Generic Host, DI, configuración y registro en Windows Forms. ↩
-
Microsoft Learn, ASP.NET Core runtime environments. Sobre DOTNET_ENVIRONMENT, ASPNETCORE_ENVIRONMENT, Production y diferencias de mayúsculas entre Windows y Linux. ↩ ↩2
-
Microsoft Learn, Options pattern in .NET - Options interfaces. Sobre vida y momento de actualización de IOptions, IOptionsSnapshot e IOptionsMonitor. ↩ ↩2
-
Microsoft Learn, Options pattern in .NET - Options validation. Sobre ValidateDataAnnotations y ValidateOnStart. ↩ ↩2 ↩3
-
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
-
Microsoft Learn, ProtectedData Class. Sobre DPAPI, Protect/Unprotect, scopes CurrentUser/LocalMachine y exclusividad de Windows. ↩ ↩2
-
Microsoft Learn, Configuration providers in .NET. Sobre integrar fuentes como JSON, variables, línea de comandos, INI y XML bajo IConfiguration. ↩
-
Microsoft Learn, Configuration providers in .NET - Environment variable configuration provider. Sobre variables
DOTNET_, configuración de host/aplicación y añadir prefijos personalizados. ↩ -
Microsoft Learn, Environment.GetFolderPath Method. Sobre Environment.SpecialFolder y GetFolderPath. ↩
-
Microsoft Learn, Detect changes with change tokens in ASP.NET Core. Sobre reloadOnChange y vigilancia con PhysicalFileProvider/FileSystemWatcher. ↩
-
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. ↩
-
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 relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Identificar qué es «lento» con PerfView y dotnet-trace — introducción práctica a la investigación de rendimiento en .NET
Qué herramientas y datos conviene mirar cuando una aplicación de negocio va lenta, mantiene la CPU al máximo o se queda congelada ocasion...
Impresión y salida PDF en aplicaciones empresariales Windows — cómo elegir System.Drawing.Printing / WPF / bibliotecas de informes
Organiza la impresión WinForms con PrintDocument, la impresión WPF con FlowDocument/FixedDocument y las alternativas de salida PDF en una...
Introducción al registro de eventos de Windows y ETW — llevar los registros de aplicaciones de negocio al mecanismo estándar del sistema operativo
¿Está resolviendo el registro de una aplicación de negocio Windows solo con archivos? El registro de eventos y ETW son una capa distinta,...
Google Ads con un presupuesto reducido para BtoB — Diseño y rutina semanal para obtener resultados con varias decenas de miles de yenes al mes
Guía práctica para empresas BtoB que quieren empezar con Google Ads con un presupuesto mensual de varias decenas de miles de yenes. Expli...
Hacer que un sitio aparezca en búsquedas por nombre de zona — Guía práctica de SEO local para pymes (páginas de área y Perfil de Empresa de Google)
Para pymes que no aparecen al buscar «nombre de zona + sector», organizamos el orden de las correcciones de SEO local: preparación del Pe...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Generic Host y arquitectura de aplicaciones
Generic Host, BackgroundService, DI, configuración, registro y ciclo de vida de la aplicación.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
El diseño de la gestión de configuración y de los archivos de ajustes forma parte de las consultas prácticas de desarrollo de aplicaciones Windows.
Consultoría técnica y revisión de diseño
Decidir una estrategia de migración desde app.config existente corresponde a la consultoría técnica con revisión de diseño.
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.
Enlaces públicos