¿Cómo accedo a Configuración en cualquier clase en ASP.NET Core?

127

He revisado la documentación de configuración en el núcleo 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.csque configuramos todas las configuraciones, Startup.cs también tiene una propiedad llamadaConfiguration

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

LP13
fuente
1
Si se trata de 4-5 pares de valores clave, puede inyectar esas configuraciones individuales. Recomendaría ese enfoque o el patrón de opciones para fines de prueba. Los tres métodos (incluido el que solicitó originalmente) se enumeran como respuestas en la siguiente pregunta duplicada posible: stackoverflow.com/questions/30263681/…
stephen.vakil
Para acceder a la configuración como un diccionario desde cualquier lugar, marque esta respuesta .
Amro
Consulte aquí para ver el ejemplo de código completo.
Arghya C
Si vienes aquí porque tienes problemas para convertir la configuración de Framework a la configuración CORE, esta respuesta es para ti stackoverflow.com/a/56498687/1704458
TS

Respuestas:

147

Actualizar

El uso de ASP.NET Core 2.0 agregará automáticamente la IConfigurationinstancia de su aplicación en el contenedor de inyección de dependencia. Esto también funciona en conjunto con ConfigureAppConfigurationel 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 IConfigurationinstancia a la colección de servicios como un objeto singleton en ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<IConfiguration>(Configuration);

   // ...
}

¿Dónde Configurationestá la instancia en tu Startupclase?

Esto le permite inyectar IConfigurationen cualquier controlador o servicio:

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}
Henk Mollema
fuente
44
Mollerna ... y ¿qué tal si desea inyectar la configuración en un proyecto de biblioteca de clases separado en la solución? Intenté así IConfiguration estática privada _configuration {get; conjunto; } Public DatabaseHelpers (configuración IConfiguration) {_configuration = configuration; } pero _ la configuración siempre es nula ... nunca se ve afectada en el constructor
dinotom
2
Dicho esto, pasar de IConfigurationesa manera es muy permeable. Mucho mejor usar el patrón Opciones .
Marc L.
77
¿Cómo acceder a los valores de "appsettings.json" directamente en una clase personalizada? ¿Sin pasar los datos de un controlador? ¿Es posible?
Tadej
2
@HenkMollema ¿Podría agregar un ejemplo de esto aquí? ¿Cómo lo inyectaría a cualquier clase (de dónde?).
Tadej
55
@HenkMollema La pregunta era cómo inyectar en cualquier clase ... no cómo inyectar en "cualquier clase resuelta mediante inyección de dependencia". Creo que ahí es donde está la falta de comunicación ... es probable que su clase no sea llamada desde una cadena que comienza con un Controlador u otro objeto resuelto automáticamente mediante un proceso DI automático.
BVernon
34

La forma correcta de hacerlo:

En .NET Core puede inyectar IConfigurationcomo 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 se inyecta IConfiguration, no podrá hacerlo new MyClass(), ya que necesita un IConfigurationparámetro inyectado en el constructor, por lo que deberá inyectar su clase como bien a la cadena de inyección, lo que significa dos pasos simples:

1) Añadir a su clase / es - en las que desee utilizar el IConfiguration, a la IServiceCollectionen el ConfigureServices()método en elStartup.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ías poder disfrutar _myClass.configurationlibremente ...

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 un static classarchivo, que configurará en Startup.cs, algo como:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Y su Startupconstructor debería verse así:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
    MyAppData.Configuration = configuration;
}

Luego, utilícelo MyAppData.Configurationen 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 es bien sabido 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 quizás también sea más seguro tener solo lo que necesita.

Mayer Spitzer
fuente
55
Toda esta inyección de archivos de configuración parece un poco inútil / desordenada. TY para la idea de clase de configuración estática.
Andrew
1
La pregunta, por supuesto, era sobre acceder a la configuración en cualquier clase y no solo en el controlador. Y si bien con el nuevo desarrollo de servicios lean (microservicios) esto puede pensarse, cuando se trata de migraciones, este es un gran dolor. Es por eso que Microsoft consiguió System.Configurationque CORE volviera a la normalidad. Ahora, puede acceder a su buena aplicación anterior. Configuraciones como en los viejos tiempos. Y no estoy hablando de controladores aquí. Estamos hablando de componentes que tienen sus propias configuraciones
TS
Permite el acceso en cualquier clase y no solo en el controlador, solo requiere ser importado al controlador para obtener la inyección de dependencia.
Mayer Spitzer
1
Cualquiera de los métodos funciona, y los argumentos a favor o en contra de cada uno son académicos en mi opinión. He usado ambos para diferentes aplicaciones ... ahora, gracias a su segunda opción extremadamente fácil. Crear una clase estática es bastante difícil con DI.
iGanja
El segundo método también ayuda con un problema común en .Net Core 2.0: objetos instanciados como un parámetro POST (es decir, deserializados automáticamente de JSON), donde no tiene la oportunidad de inyectar en el constructor (al menos no sin mucho de código extra). Esto funciona muy bien para ese escenario
Joe Moon
30

Sé que esto es antiguo, pero dados los patrones de IOptions es relativamente simple de implementar:

  1. 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; }
    }
  2. registre su configuración

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. 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.

ScottC
fuente
2
¿Cómo acceder a los valores de "appsettings.json" directamente en una clase personalizada?
Tadej
2
@JedatKinports es necesario agregar dependencias Nuget Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Bindery Microsoft.Extensions.Configuration.Jsona continuación, cargar appsettings.jsonarchivos como var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();..y también hay que asegurarse de que appsettings.jsonla copia en el directorio de salida se ajusta acopy always
LP13
7

También hay una opción para hacer configurationestá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?

konzo
fuente
6

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"]
Tadej
fuente
3

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
}
Pieter Heemeryck
fuente
¿Funciona sin mencionar explícitamente MyClass en Startup.cs, algo como esto? services.AddTransient <MyClass> ();
El padrino
Sí, en realidad, debe mencionar las clases que desea inyectar en Startup.cs, no al revés. Pero IConfiguration creo que, por defecto, ya está disponible para inyectar.
Pieter Heemeryck
Si, funciona. Intenté esto después de hacer el comentario y la implementación de la configuración se inyectó en IConfiguration. Gracias de todos modos :)
The Godfather
1
@netfed Como Mayer Spitzer afirma en su respuesta, por supuesto, tendrá que agregar MyClass al inicio e inyectarlo donde lo necesite, por lo que no necesita crear una nueva instancia de MyClass usted mismo, lo inyecta donde lo necesita.
Pieter Heemeryck
2

Sé que puede haber varias formas de hacer esto, estoy usando Core 3.1 y estaba buscando la opción óptima / más limpia y terminé haciendo esto:

  1. Mi clase de inicio es la predeterminada
public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}
  1. Mi appsettings.json es así
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Mi clase es un controlador de API, así que primero agregué la referencia de uso y luego inyecté la interfaz IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Finalmente utilicé el método GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}
usuario1058637
fuente
0

En 8-2017, Microsoft salió con System.Configuration.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 app.configarchivos actuales , a los que se puede acceder desde cualquier ensamblaje. Es probable que incluso sea una alternativa appsettings.json, ya que Microsoft se dio cuenta de la necesidad. Funciona igual que antes en FW. Hay una diferencia:

En las aplicaciones web, [por ejemplo, ASP.NET CORE WEB API] debe usar app.configy no web.config para su appSettingso configurationSection. Es posible que necesite usar, web.configpero solo si implementa su sitio a través de IIS. Coloca configuraciones específicas de IIS enweb.config

Lo probé con netstandard20 DLL y Asp.net Core Web Api y todo funciona.

TS
fuente
0

Usar el patrón de Opciones en ASP.NET Core es el camino a seguir. Solo quiero agregar, si necesita acceder a las opciones dentro de su startup.cs , le recomiendo hacerlo de esta manera:

CosmosDbOptions.cs:

public class CosmosDbOptions
{
    public string ConnectionString { get; set; }
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // This is how you can access the Connection String:
    var connectionString = Configuration.GetSection(nameof(CosmosDbOptions))[nameof(CosmosDbOptions.ConnectionString)];
}
Martin Brandl
fuente
Entonces, si tengo una subsección completa con una docena de valores de configuración a los que necesito acceder en ConfigureServices, ¿debo hacerlo para todos ellos? ¿No hay otra forma de hacer esto a través del patrón IOptions? Necesito inyectar esto en un método de extensión estática donde estoy configurando mi bus de transporte público. Además, ¿qué pasa con esta sugerencia de Microsoft sobre no usar el patrón IOptions en ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
Kuldeep
No uso IOPtions en ConfigureService aquí ...
Martin Brandl
-3

Tengo que leer los propios parámetros al inicio.
Eso tiene que estar allí antes de que se inicie el WebHost (ya que necesito la url / IP "para escuchar" y el puerto del archivo de parámetros y aplicarlo al 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, he decidido hacerlo "a la antigua usanza" con un archivo .ini propio.
Entonces ... si quieres usar tu propio archivo .ini y / o configure el "para escuchar url / IP" propio y / o necesite la configuración pública, esto es para usted ...

Ejemplo completo, válido para core 2.1 (mvc):

Crear un archivo .ini - ejemplo:

[Inicio]
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 rojo la información está en la consola (incluida la excepción) y también puedo reaccionar en la aplicación (GV.bFehler_Ini se establece en verdadero, si hay errores con el .ini)
FredyWenger
fuente