Reagire alle modifiche della configurazione di ASP.NET Core

di Marco De Sanctis, in ASP.NET Core,

La gestione della configurazione in ASP.NET Core è divenuta parecchio più avanzata rispetto a quanto accadeva in ASP.NET classico. Al di là della maggiore espressività dei file json, c'è anche una migliore gestione del reload dei dati di configurazione senza che questo provochi un ricilo dell'applicazione stessa.

In questo e nel corso dei prossimi script, vedremo alcuni esempi su come gestire queste modifiche, iniziando dalla tecnica più basilare di tutte, ossia utilizzando direttamente il servizio IConfiguration.

Immaginiamo allora di avere impostato una chiave di configurazione myValue su appsettings.json:

{
  "Logging": {
    ...
  },
  "myValue": "value1"
}

Per visualizzare la chiave letta, useremo un controller al quale abbiamo iniettato direttamente IConfiguration:

[Route("[controller]")]
[ApiController]
public class ConfigDemoController : ControllerBase
{
    private static DateTime _timestamp = DateTime.Now;
    private IConfiguration _config;

    public ConfigDemoController(IConfiguration config)
    {
        _config = config;
    }

    [HttpGet]
    public string Get()
    {
        return $"{_timestamp}: {_config.GetValue<string>("myValue")}";
    }
}

Il controller ha anche un timestamp static, che pertanto viene inizializzato una sola volta per ciclo di vita dell'applicazione, e possiamo utilizzare per verificare se sia avvenuto un riciclo.

Come possiamo sperimentare, ogni volta che invochiamo questo controller, il timestamp resterà il medesimo, ma se variamo il valore su appsettings.json, il controller mostrerà il valore più aggiornato.

Questo è possibile grazie al fatto che IConfiguration istanzia interamente un FileSystemWatcher che monitora i file di configurazione e solleva un evento nel caso in cui vengano modificati, provocando una rilettura della configurazione stessa. In altri termini, IConfiguration esporrà sempre la configurazione più recente, evitando allo stesso tempo di leggere continuamente su FileSystem.

Se invece che in un controller dobbiamo passare questi dati a un servizio, dobbiamo tenere conto del fatto che la classe Startup verrà eseguita solo all'avvio dell'applicazione. Pertanto, se passassimo il valore di configurazione in maniera statica come nell'esempio in basso, perderemmo il beneficio del refresh che abbiamo visto finora:

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    // così leggiamo il valore una sola volta e ignoreremo tutti gli aggiornamenti
    var value = Configuration.GetValue<string>("myValue");

    services.AddTransient<MyService>(sp => new MyService(value));
}

Il modo corretto è di sfruttare invece il ServiceProvider passato nella lambda, per recuperare l'istanza di IConfiguration da cui leggere il setting:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddTransient(sp => 
    {
        var config = sp.GetRequiredService<IConfiguration>();

        return new MyService(config.GetValue<string>("myValue"));
    });
}

Come detto all'inizio dello script, questo è il modo più basilare e semplice per leggere la configurazione più aggiornata, ma non è esente da difetti: per esempio, può risultare complesso far sì che tutti i componenti di una richiesta leggano lo stesso valore, se la modifica avviene concorrentemente all'esecuzione della richiesta stessa. Oppure, effettuare il refresh dei setting in una classe registrata come singleton.

Di questi aspetti ci occuperemo nei prossimi script.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi