Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 15 de marzo de 2016
ASP.NET Core
Seguro que estamos todos de acuerdo en que el nuevo sistema de configuración proporcionado por ASP.NET Core mejora bastante lo que teníamos en las versiones más tradicionales de ASP.NET.

Y la posibilidad de almacenar settings en formatos como .INI o .XML resulta interesante, el formato JSON me parece de lo más cómodo y apropiado para muchos escenarios en los que antes no lo teníamos tan sencillo, como definir configuraciones con un cierto nivel de jerarquía como la siguiente:

{
  "appName": "My App",
  "version":  "1.0 beta",
  "notifications": {
    "enabled":  true,
    "server": {
      "smtp": "smtp.myserver.com",
      "user": "myuser",
      "pass": "1234"
    },
    "targets": {
      "warnings": "dev@mycompany.com",
      "errors": [
        "dev@mycompany.com",
        "support@mycompany.com"
      ]
    }
  }
}
Como sabemos, para acceder de forma directa a estos valores, basta con:
  • Primero, en el constructor de la clase de inicialización de ASP.NET Core, cargar los archivos de settings que nos interesen y construir una instancia de IConfiguration para usarla a más adelante.
    private IConfiguration Configuration { get; set; }
    public Startup()
    {
        var configurationBuilder = new ConfigurationBuilder()
            .AddJsonFile("myConfig.json")
            // Add other files here
            .AddEnvironmentVariables();
    
        this.Configuration = configurationBuilder.Build();
    }
  • Segundo, registrar en el sistema de inyección de dependencias la instancia obtenida anteriormente, de forma que quedará disponible para todos los componentes que deseen acceder a la configuración:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IConfiguration>(this.Configuration);
    }
  • A continuación, utilizar el sistema de inyección de dependencias para reclamar la instancia que nos da acceso a la configuración, por ejemplo añadiendo un parámetro de tipo IConfiguration al constructor del componente desde el que queremos acceder a los settings y usándolo para obtener sus valores. Por ejemplo, en el caso de un controlador MVC podría ser algo así:
    public class HomeController : Controller
    {
        private readonly IConfiguration _config;
    
        public HomeController(IConfiguration config)
        {
            _config = config;
        }
    
        public IActionResult Index()
        {
            return Content(_config["appName"]); // Shows "My App"
        }
    }
En el código anterior podemos observar el uso del indexador del objeto IConfiguration para acceder a los valores de forma directa, e incluso utilizando como separador el carácter dos puntos ":", podemos navegar libremente por la jerarquía de la configuración hasta obtener el valor buscado. Por ejemplo, en el caso anterior, la expresión _config["notifications:server:smtp"] retornaría el valor "smtp.myserver.com".

Sin embargo, cuando el valor de un parámetro de configuración es un array, no está tan claro cuál sería la forma de acceder a los elementos de esta colección. Para verlo con un ejemplo, imaginemos la siguiente porción de configuración:
{
  "foo": {
    "bar": [
      "one",
      "two"
    ]
  }
}
En este caso la sintaxis no es tan intuitiva: si queremos acceder a un elemento concreto del array de valores podemos utilizar su índice (base cero) como parte de la cadena de acceso, separándolo de nuevo por los dos puntos. Así, la expresión _config["foo:bar:0"] retornaría "one", mientras que con _config["foo:bar:1"] obtendríamos el valor "two".

La misma técnica es aplicable si se trata de un array de objetos, a cuyos elementos podemos acceder de forma directa:
// appsettings.json:
...
"foo": {
  "bar": [
    { "number":  "one" },
    { "number":  "two" }
  ]
}
...

// Acceso:
var x = _config["foo:bar:1:number"]; // "two"
Si queremos enumerar todos los elementos de configuración que cuelgan de un nodo determinado, podemos utilizar el método GetChildren(), que nos devolverá una colección de secciones en forma de instancias de IConfigurationSection donde, a su vez, podemos realizar consultas usando la misma sintaxis anterior.
var items = _config.GetSection("foo:bar").GetChildren();
var result = items.Select(i => i["number"]); 
// -> {"one", "two"}
¿Y si estamos usando settings tipados, cómo obtenemos los elementos de un array? Pues en este caso lo tendremos incluso más sencillo, porque simplemente tendremos que definir en nuestra clase de settings personalizados el array de elementos
// Clase de settings personalizados

public class MyAppSettings
{
    public FooSetting Foo { get; set; }
}

public class FooSetting
{
    public NumberSetting[] Bar { get; set; }
}

public class NumberSetting
{
    public string Number { get; set; }
}

// Registro de clase de settings personalizados (Startup.cs)

...
services.Configure<MyAppSettings>(Configuration)
...

// Acceso a elemento del array usando DI:

public HomeController(IOptions<MyAppSettings> myAppSettings)
{
    _myAppSettings = myAppSettings;
    var value = _myAppSettings.Value.Foo.Bar[1].Number; // "two"
    ...
}
¡Y eso es todo! Espero que esta revisión del sistema de configuración, y en particular de las técnicas para acceder a arrays de settings os resulte de ayuda cuando empecéis a trabajar con el nuevo framework.

Publicado en Variable not found.

2 Comentarios:

Unknown dijo...

Hola Jose! Muy interesante y útil tu post. Quería agregar en la parte de Inyección de Dependencias debería ser así por lo menos a mi me funciono de esta forma.

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(provider => this.Configuration);
}


Saludos
Amed

José María Aguilar dijo...

Hola!

Genial, muchas gracias por aportar! No lo recuerdo con exactitud, pero probablemente lo probaría con alguna versión anterior a la actual, y haya cambiado el registro desde entonces. De hechom con la próxima RC2 también vienen cambios al respecto.

Saludos!