Nello script precedente (https://www.aspitalia.com/script/1403/Reagire-Modifiche-Configurazione-ASP.NET-Core.aspx) abbiamo visto che possiamo iniettare un'istanza di IConfiguration nei nostri servizi e usarla per leggere i valori più aggiornati della configurazione.
Tuttavia, questa soluzione soffre di alcuni problemi:
- la lettura dei dati fa uso di magic string e pertanto tende a essere un po' problematica se dobbiamo effettuare dei refactoring, oltre che prona agli errori;
- la rilettura della configurazione avviene sì in automatico, ma in maniera incontrollata. C'è per esempio il rischio che, se la modifica dei setting avviene in concomitanza con una richiesta, due servizi di quest'ultima richiesta possano leggere due dati diversi;
- possiamo utilizzare solo assegnazioni di tipi nativi, se invece dobbiamo configurare oggetti più complessi (per es. un delegate) la soluzione non è così banale.
Per ovviare a queste problematiche, possiamo utilizzare il cosiddetto Options Pattern.
Cerchiamo di capire di cosa si tratta.
Come prima cosa, dobbiamo creare una classe che rappresenta la parte della configurazione che vogliamo passare al nostro oggetto. Per esempio, per una sezione di appsettings.json come la seguente
{ ... "option": { "MyStringValue": "value1" }, .... }
possiamo creare una classe simile:
public class ValueOption { public string MyStringValue { get; set; } }
A questo punto, nel nostro Startup, possiamo configurare ValueOption associandola alla relativa sezione di appSettings:
public void ConfigureServices(IServiceCollection services) { // ...altro codice qui... services.Configure<ValueOption>(Configuration.GetSection("option")); }
Spostiamo ora la nostra attenzione a come possiamo iniettare questa classe nei nostri componenti. Il modo più basilare è usare l'interfaccia generica IOptions<T>:
public ConfigDemoController(IOptions<ValueOption> option) { _option = option; } [HttpGet] public string Get() { return $"{_timestamp}: {_option.Value.MyStringValue}"; }
Attenzione, però: questa interfaccia non supporta il reload della configurazione. Pertanto, è da utilizzare solo per quelle impostazioni il cui valore assumiamo essere fisso per tutto il ciclo di vita dell'applicazione.
Se invece vogliamo supportare il refresh, dobbiamo iniettare un oggetto di tipo IOptionsSnapshot<T>:
public ConfigDemoController(IOptionsSnapshot<ValueOption> option) { _option = option; } [HttpGet] public string Get() { return $"{_timestamp}: {_option.Value.MyStringValue}"; }
Il codice è assolutamente analogo, ma al contrario del caso precedente, in questo secondo esempio vedremo il valore aggiornarsi, modificando il contenuto di appsettings.json. Un dettaglio importante è che IOptionsSnapshot<T> è registrata come Scoped. Questo vuol ci garantisce che, nel contesto di una singola richiesta, il valore dei setting resterà costante, anche se ci dovesse essere una modifica concorrente.
Il ciclo di vita Scoped ha come effetto collaterale che, ovviamente, non possiamo utilizzarla con oggetti di tipo Singleton. In un prossimo script scopriremo come ovviare a questa limitazione.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Applicare il versioning ai nostri endpoint ASP.NET Core Minimal API
Utilizzare gli snapshot con Azure File shares
Gestire errori funzionali tramite exception in ASP.NET Core Web API
Ottimizzare la latenza in Blazor 8 tramite InteractiveAuto render mode
Load test di ASP.NET Core con k6
Evitare (o ridurre) il repo-jacking sulle GitHub Actions
Migrare una service connection a workload identity federation in Azure DevOps
Ottimizzazione dei block template in Angular 17
Assegnare un valore di default a un parametro di una lambda in C#
Effettuare lo stream della risposta in ASP.NET Core tramite IAsyncEnumerable
Usare un KeyedService di default in ASP.NET Core 8
Creare gruppi di client per Event Grid MQTT