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
Ordinare randomicamente una lista in C#
Hosting di componenti WebAssembly in un'applicazione Blazor static
Bloccare l'esecuzione di un pod in mancanza di un'artifact attestation di GitHub
Il nuovo controllo Range di Blazor 9
Sfruttare GPT-4o realtime su Azure Open AI per conversazioni vocali
Creare un'applicazione React e configurare Tailwind CSS
Definire stili a livello di libreria in Angular
Garantire la provenienza e l'integrità degli artefatti prodotti su GitHub
Utilizzare un numero per gestire la concorrenza ottimistica con SQL Server ed Entity Framework
Modificare i metadati nell'head dell'HTML di una Blazor Web App
Migliorare la scalabilità delle Azure Function con il Flex Consumption
Esporre i propri servizi applicativi con Semantic Kernel e ASP.NET Web API