Basta ya de buscar por todo internet porque llegaste al espacio justo, contamos con la solución que quieres hallar y sin liarte.
Solución:
Creo que esta tiene la respuesta aburrida; depende. Pero mi enfoque favorito es este:
appsetting.json (base settings)
appsettings.development.json (dev with no secrets)
appsettings.production.json (production with no secrets)
Appsettings donde los valores que son secretos solo existen en la configuración base, mientras que los demás están escritos en los respectivos appsettings.[env].json. Entonces ejemplo de conexión a la base de datos key solo existe en la configuración básica con la base de datos local. Es el trabajo del medio ambiente reemplazarlo
Ejemplo de conexión y registro de base de datos
appsettings.json
"ConnectionStrings":
“dbConnection: “data source=localhost” <—— only here
,
“environment”: “local”,
"Logging":
"LogLevel":
"Default": “Verbose”
,
appsettings.development.json
“environment”: “development”,
"Logging":
"LogLevel":
"Default": “Warning”
,
appsettings.production.json
“environment”: “production”,
"Logging":
"LogLevel":
"Default": “Information”
,
Mi preocupación es: digamos que una aplicación se implementa en un servidor en vivo, pero un key
almacenado en una variable de entorno (por ejemplo, para anular la conexión string) falta o está mal escrito, etc. En este caso, la aplicación volvería a la conexión base appsettings.json string cuál sería la base de datos incorrecta para el entorno en vivo. Un escenario como este suena bastante desastroso, especialmente porque esto podría pasar desapercibido fácilmente.
Siempre puedes hacer esto. Pero algunas pruebas de cordura deberían hacerlo. Realice una verificación de estado simple en la que haga ping a la base de datos si su infraestructura / canal de implementación lo permite.
Hay varias formas de dar forma a la configuración (esa es la belleza de .NET Core). La forma en que lo hago normalmente es la siguiente:
appsetting.json (template)
appsettings.development.json (dev with no secrets)
De hecho, no puse ninguna configuración en appsettings.json. Lo uso como un mapa de plantilla de la configuración que debe (puede) establecerse durante la implementación.
// appsettings.json
"ConnectionStrings":
“dbConnection: "************************"
,
“environment”: “************************”,
"Logging":
"LogLevel":
"Default": “************************”
,
De esa forma, si me olvido de algún ajuste, más adelante se hará evidente que se olvidó. No tengo que preocuparme por el uso accidental de configuraciones que "se deslizaron" a través de la jerarquía. Por lo tanto, si observa sus otros jsons, están completos y no hay configuraciones ocultas.
// appsettings.Development.json
"ConnectionStrings":
“dbConnection: “data source=localhost”
,
“environment”: “local”,
"Logging":
"LogLevel":
"Default": “Verbose”
Compartir configuraciones parece ser una buena idea para aplicaciones pequeñas. En realidad, da más problemas si su aplicación se vuelve más compleja.
He adquirido el hábito de almacenar mi configuración en Azure en AzureAppConfig y / o AzureKeyVault. Me brinda una ubicación central para administrar mi configuración de desarrollo, preparación / prueba, producción y no requiere que complique mi implementación manipulando archivos de configuración de aplicaciones o almacenándolos en algún tipo de repositorio de implementación. En realidad, solo se lee desde azul cuando se inicia la aplicación (no necesitaba poder actualizarlos mientras mi aplicación se estaba ejecutando). Dicho esto, lo hizo un poco interesante para la historia del desarrollador local porque yo personalmente quería que el orden de las operaciones fuera appsettings.json
, appsettings.environment.json
, AzureAppConfig
, KeyVault
, entonces finalmente secrets.json
. De esa manera, pase lo que pase, podría anular una configuración de azul con mi archivo de secretos locales (incluso si la configuración que estaba anulando no era técnicamente un secreto).
Básicamente terminé escribiendo un código personalizado en program.cs
para manejar la carga de las fuentes de configuración desde Azure, luego termine buscando el JsonConfigurationSource
que tenia un Path
de "secrets.json"
, luego colóquelo para que sea el último elemento de mi IConfigurationBuilder.Sources
.
Para mí, mis archivos se utilizan de la siguiente manera
appsettings.json
- Configuraciones comunes que deberían establecerse para cualquier entorno, y probable nunca cambien dependiendo del entorno.
appsettings.environment.json
- En su mayoría solo archivos JSON vacíos que básicamente solo nombran elAzureAppConfig
YAzuerKeyVault
nombres de recursos a los que conectarseAzureAppConfig
- Básicamente para cualquier cosa que sea diferente entre producción, puesta en escena / pruebas o desarrollo local, Y no es una información confidencial. Direcciones de puntos finales de API, direcciones IP, varias URL, información de registro de errores, ese tipo de cosas.AzureKeyVault
- Cualquier cosa sensible. Nombres de usuario, contraseñas, keys para API externas (autenticación, licencia keys, cadenas de conexión, etc.).
La cuestión es que, incluso si pones un ajuste en appsettings.json
, eso no significa que no pueda anularlo con appsettings.enviroment.json
o en otro sitio. Con frecuencia puse una configuración en el archivo de configuración raíz con un valor de NULL
, solo para recordarme que es una configuración utilizada en la aplicación. Entonces, una mejor pregunta podría ser, ¿desea poder ejecutar su aplicación (como sin errores) con nada más que la base appsettings.json
y secrets.json
? ¿O el contenido de appsettings.enviroment.json
siempre será necesario para girar con éxito?
La otra cosa a tener en cuenta en función de su pregunta es la validación de su configuración. Versiones posteriores de Microsoft.Extensions.Options
ofrecen varias formas de validar sus opciones para que pueda intentar detectar instancias en las que algo quedó vacío / indefinido. Normalmente decoro mis clases de opciones de POCO con anotaciones de datos attributes y luego usa ValidateDataAnnotations()
para verificar que se hayan configurado correctamente.
Por ejemplo
services.AddOptions().Bind(configuration.GetSection("MailSettings")).ValidateDataAnnotations();
Vale la pena señalar que esta validación se ejecuta solo cuando intenta solicitar algo como el MailOptions
Utilizo como ejemplo anterior, de DI (por lo que no al inicio) Por esta razón, también creé el mío propio IStartupFilter
para solicitar de forma preventiva una o más de mis clases de Opciones del proveedor de servicios cuando se inicia la aplicación, para forzar la ejecución de esa misma Validación antes de que la aplicación comience a aceptar solicitudes.
public class EagerOptionsValidationStartupFilter : IStartupFilter
public readonly ICollection EagerValidateTypes = new List();
private readonly IServiceProvider serviceProvider;
public EagerOptionsValidationStartupFilter(IServiceProvider serviceProvider)
this.serviceProvider = serviceProvider;
public Action Configure(Action next)
foreach (var eagerType in EagerValidateTypes)
dynamic test = serviceProvider.GetService(typeof(IOptions<>).MakeGenericType(eagerType));
_ = test.Value;
return next;
startup.cs
public void ConfigureServices(IServiceCollection services)
services.AddTransient(x =>
new EagerOptionsValidationStartupFilter(x)
EagerValidateTypes =
typeof(MailOptions),
typeof(OtherOptions),
typeof(MoreImportantOptions)
);