c# - nswag - ¿Cómo accedo a Configuración en cualquier clase en ASP.NET Core?
tag helpers asp net core (8)
He revisado la documentación de configuración en el núcleo de ASP.NET. La documentación dice que puede acceder a la configuración desde cualquier lugar de la aplicación.
A continuación se muestra Startup.cs creado por plantilla
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
}
}
Entonces, en
Startup.cs
configuramos todas las configuraciones, Startup.cs también tiene una propiedad llamada
Configuration
¿Qué no puedo entender cómo accede a esta configuración en el controlador o en cualquier lugar de la aplicación? MS recomienda usar el patrón de opciones, pero solo tengo 4-5 pares clave-valor, por lo que me gustaría no usar el patrón de opciones. Solo quería tener acceso a Configuración en la aplicación. ¿Cómo lo inyecto en cualquier clase?
La forma correcta de hacerlo:
En .NET Core puede inyectar la
IConfiguration
como parámetro en su constructor de Clase, y estará disponible.
public class MyClass
{
private IConfiguration configuration;
public MyClass(IConfiguration configuration)
{
ConnectionString = new configuration.GetValue<string>("ConnectionString");
}
Ahora, cuando desee crear una instancia de su clase, ya que su clase está inyectando la
IConfiguration
, no podrá simplemente hacer un
new MyClass()
, porque necesitará pasar el parámetro
IConfiguration
al constructor, entonces, necesitará inyectar su clase también en la cadena de inyección, lo que significa dos pasos simples:
1) Agregue su / s clase / s - donde quiera usar
IConfiguration
, a
IServiceCollection
en el método
ConfigureServices()
en
Startup.cs
services.AddTransient<MyClass>();
2) Defina una instancia, digamos en el
Controller
, e inyecte usando el constructor:
public class MyController : ControllerBase
{
private MyClass _myClass;
public MyController(MyClass myClass)
{
_myClass = myClass;
}
Ahora debería poder disfrutar de su
_myClass.configuration
libremente ...
Otra opción:
Si todavía está buscando una manera de tenerlo disponible sin tener que inyectar las clases en el controlador, puede almacenarlo en una
static class
, que configurará en
Startup.cs
, algo así como:
public static class MyAppData
{
public static IConfiguration Configuration;
}
Y su constructor de
Startup
debería verse así:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
MyAppData.Configuration = configuration;
}
Luego use
MyAppData.Configuration
en cualquier parte de su programa.
No me enfrente por qué la primera opción es la correcta, solo puedo ver que los desarrolladores experimentados siempre evitan los datos basura en su camino, y se entiende que no es la mejor práctica tener un montón de datos disponibles en la memoria todo el tiempo, ni es bueno para el rendimiento ni para el desarrollo, y tal vez también sea más seguro tener solo lo que necesita.
Actualizar
El uso de ASP.NET Core 2.0 agregará
automatically
la instancia de
IConfiguration
de su aplicación en el contenedor de inyección de dependencia.
Esto también funciona junto con
ConfigureAppConfiguration
en
WebHostBuilder
.
Por ejemplo:
public static void Main(string[] args)
{
var host = WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.AddIniFile("foo.ini");
})
.UseStartup<Startup>()
.Build();
host.Run();
}
Es tan fácil como agregar la instancia de
IConfiguration
a la colección de servicios como un objeto único en
ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
// ...
}
Donde
Configuration
es la instancia en su clase de
Startup
.
Esto le permite inyectar
IConfiguration
en cualquier controlador o servicio:
public class HomeController
{
public HomeController(IConfiguration configuration)
{
// Use IConfiguration instance
}
}
En 8-2017, Microsoft lanzó
System.Configuration
para .NET CORE v4.4.
Actualmente v4.5
y v4.6 vista previa.
Para aquellos de nosotros, que trabajamos en la transformación de .Net Framework a CORE, esto es esencial.
Permite mantener y usar los archivos actuales de
app.config
, a los que se puede acceder desde cualquier ensamblaje.
Probablemente incluso sea una alternativa a
appsettings.json
, ya que Microsoft se dio cuenta de la necesidad.
Funciona igual que antes en FW.
Hay una diferencia:
En las aplicaciones web, [p. Ej., ASP.NET CORE WEB API] debe usar
app.config
y
no
web.config para su
configurationSection
appSettings
o
configurationSection
.
Es posible que deba usar
web.config
pero solo si implementa su sitio a través de IIS.
Coloca configuraciones específicas de IIS en
web.config
Lo probé con netstandard20 DLL y Asp.net Core Web Api y todo funciona.
Lo estoy haciendo así en este momento:
// Requires NuGet package Microsoft.Extensions.Configuration.Json
using Microsoft.Extensions.Configuration;
using System.IO;
namespace ImagesToMssql.AppsettingsJson
{
public static class AppSettingsJson
{
public static IConfigurationRoot GetAppSettings()
{
string applicationExeDirectory = ApplicationExeDirectory();
var builder = new ConfigurationBuilder()
.SetBasePath(applicationExeDirectory)
.AddJsonFile("appsettings.json");
return builder.Build();
}
private static string ApplicationExeDirectory()
{
var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
var appRoot = Path.GetDirectoryName(location);
return appRoot;
}
}
}
Y luego uso esto donde necesito obtener los datos del archivo appsettings.json:
var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]
Miré la muestra del patrón de opciones y vi esto:
public class Startup
{
public Startup(IConfiguration config)
{
// Configuration from appsettings.json has already been loaded by
// CreateDefaultBuilder on WebHost in Program.cs. Use DI to load
// the configuration into the Configuration property.
Configuration = config;
}
...
}
Al agregar Iconfiguration en el constructor de mi clase, pude acceder a las opciones de configuración a través de DI.
Ejemplo:
public class MyClass{
private Iconfiguration _config;
public MyClass(Iconfiguration config){
_config = config;
}
... // access _config["myAppSetting"] anywhere in this class
}
Sé que esto es antiguo, pero dados los patrones de IOptions es relativamente simple de implementar:
-
Clase con propiedades públicas get / set que coinciden con la configuración en la configuración
public class ApplicationSettings { public string UrlBasePath { get; set; } }
-
registre su configuración
public void ConfigureServices(IServiceCollection services) { ... services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings")); ... }
-
inyectar a través de IOptions
public class HomeController { public HomeController(IOptions<ApplicationSettings> appSettings) { ... appSettings.Value.UrlBasePath ... // or better practice create a readonly private reference } }
No estoy seguro de por qué no harías esto.
También hay una opción para hacer que la
configuration
estática en startup.cs para que pueda acceder a ella desde cualquier lugar con facilidad, las variables estáticas son convenientes, ¿eh?
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
internal static IConfiguration Configuration { get; private set; }
Esto hace que la configuración sea accesible desde cualquier lugar usando
Startup.Configuration.GetSection...
¿Qué puede salir mal?
Tengo que leer los propios parámetros al inicio.
Eso tiene que estar allí
antes de que
se inicie WebHost (ya que necesito la url / IP "para escuchar" y el puerto del archivo de parámetros y aplicarlo a WebHost).
Además, necesito la configuración
pública
en toda la aplicación.
Después de buscar durante un tiempo (no se encontró un ejemplo completo, solo fragmentos) y después de varios intentos y errores, decidí hacerlo "a la antigua usanza" con un archivo .ini propio.
Entonces ... si desea usar su propio archivo .ini y / o configurar el "escuchar url / IP" y / o necesita la configuración pública, esto es para usted ...
Ejemplo completo, válido para core 2.1 (mvc):
Crear un archivo .ini - ejemplo:
[Puesta en marcha]
URL = http://172.16.1.201:22222
[Parámetro]
* Dummy1 = gew7623
Dummy1 = verdadero
Dummy2 = 1
por lo que los Dummyx solo se incluyen como ejemplo para otros tipos de fechas que no sean cadenas (y también para probar el caso "parámetro incorrecto" (ver código a continuación).
Se agregó un archivo de código en la raíz del proyecto, para almacenar las variables globales:
namespace MatrixGuide
{
public static class GV
{
// In this class all gobals are defined
static string _cURL;
public static string cURL // URL (IP + Port) on that the application has to listen
{
get { return _cURL; }
set { _cURL = value; }
}
static bool _bdummy1;
public static bool bdummy1 //
{
get { return _bdummy1; }
set { _bdummy1 = value; }
}
static int _idummy1;
public static int idummy1 //
{
get { return _idummy1; }
set { _idummy1 = value; }
}
static bool _bFehler_Ini;
public static bool bFehler_Ini //
{
get { return _bFehler_Ini; }
set { _bFehler_Ini = value; }
}
// add further GV variables here..
}
// Add further classes here...
}
Cambió el código en program.cs (antes de CreateWebHostBuilder ()):
namespace MatrixGuide
{
public class Program
{
public static void Main(string[] args)
{
// Read .ini file and overtake the contend in globale
// Do it in an try-catch to be able to react to errors
GV.bFehler_Ini = false;
try
{
var iniconfig = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddIniFile("matrixGuide.ini", optional: false, reloadOnChange: true)
.Build();
string cURL = iniconfig.GetValue<string>("Startup:URL");
bool bdummy1 = iniconfig.GetValue<bool>("Parameter:Dummy1");
int idummy2 = iniconfig.GetValue<int>("Parameter:Dummy2");
//
GV.cURL = cURL;
GV.bdummy1 = bdummy1;
GV.idummy1 = idummy2;
}
catch (Exception e)
{
GV.bFehler_Ini = true;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("!! Fehler beim Lesen von MatrixGuide.ini !!");
Console.WriteLine("Message:" + e.Message);
if (!(e.InnerException != null))
{
Console.WriteLine("InnerException: " + e.InnerException.ToString());
}
Console.ForegroundColor = ConsoleColor.White;
}
// End .ini file processing
//
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>() //;
.UseUrls(GV.cURL, "http://localhost:5000"); // set the to use URL from .ini -> no impact to IISExpress
}
}
De esta manera:
- La configuración de mi aplicación está separada de appsettings.json y no tengo efectos secundarios que temer, si MS cambia en versiones futuras ;-)
- Tengo mi configuración en variables globales
- Puedo configurar la "url de escucha" para cada dispositivo, la aplicación se ejecuta (mi máquina de desarrollo, el servidor de intranet y el servidor de internet)
- Puedo desactivar la configuración, a la antigua usanza (solo establezca un * antes)
-
Soy capaz de reaccionar, si algo está mal en el archivo .ini (por ejemplo, no coinciden los tipos)
Si, por ejemplo, se establece un tipo incorrecto (por ejemplo, * Dummy1 = gew7623 está activado en lugar de Dummy1 = true), el host muestra información roja en la consola (incluida la excepción) y puedo reaccionar también en la aplicación (GV .bFehler_Ini se establece en verdadero, si hay errores con el .ini)