LA CONFIGURAZIONE IN ASP.NET CORE MVC
ACCEDERE AI VALORI DI CONFIGURAZIONE CON IL SERVIZIO ICONFIGURATION
La configurazione è un servizio che ci consentirà di tenere i parametri di funzionamento dell’applicazione al di fuori del codice C#. Li terremo in un file JSON senza essere costretti a ricompilare l’applicazione dopo una modifica. In questo modo se l’applicazione l’abbiamo venduta a un cliente potrà modificare la configurazione senza conoscere il funzionamento interno. Creiamo un file appsettings.json, l’applicazione è già predisposta a leggere i valori da questo file, ovviamente se presente. Ecco il codice per ottenere la ConnectionString al database. Nota come sia stato configurato nel costruttore il servizio IConfiguration.
Questo è il file JSON.
Se il valore C è una stringa possiamo usare l’ultima parte riportata nella slide.
USARE UNA CONFIGURAZIONE FORTEMENTE TIPIZZATA CON IL SERVIZIO IOPTIONSMONITOR<T>
Abbiamo visto che per ottenere una connectionString abbiamo dovuto fornire dei parametri di tipo stringa in GetSection(…) e GetValue<T>(…). Ora l’abbiamo detto più volte quando abbiamo a che fare con delle stringhe possiamo fare errori di digitazione. Vediamo come accedere in maniera fortemente tipizzata al file appsettings.json. Creiamo una nuova classe nel folder Options ConnectionStringsOptions.cs. Ora andiamo a registrare questa classe nel file Startup.cs. Ecco una slide riepilogativa.
Vediamo il codice.
Vediamo ora come sia possibile leggere dei valori annidati in appsettings.json sempre in maniera fortemente tipizzata.
Vediamo la classe.
Questa è l’implementazione di IOptionsMonitor<T>.
FONTI DI CONFIGURAZIONE
I valori di configurazione non sono tutti uguali perché alcuni hanno requisiti di sensibilità diversa. Ad esempio, il numero di corsi per pagina non è un’informazione sensibile, mentre invece una ConnectionString a SQLServer potrebbe contenere informazioni sensibili, come lo User Name, la password e l’indirizzo ip del server. Per evitare di divulgare queste informazioni ASP.NET Core ci mette a disposizione diverse fonti di configurazione.
La fonte meno prioritaria può essere sovrascritta da una fonte a priorità maggiore. Se voglio ridefinire il valore PerPage in appsettings.development.json e scrivo il valore 20 questo sovrascriverà il valore 10 impostato in appsettings.json perché la priorità della fonte di configurazione è maggiore.
ALTRE FONTI DI CONFIGURAZIONE
Vediamo gli user secrets che vengono tenuti lontani dal progetto. Se ad esempio io e il mio collega abbiamo bisogno di lavorare con ConnectionString differenti fino a che siamo in sviluppo possiamo usare questa fonte di configurazione.
Nella figura le parti evidenziate in rosso rappresentano la chiave e il valore.
Vediamo le variabili d’ambiente.
L’ultima tipologia sono i parametri da riga di comando, non aggiornabili a caldo come user secrets e variabili di ambiente ma riavviando la macchina.
IL SERVIZIO DI CONFIGURAZIONE
La maggior parte delle applicazioni è abbastanza flessibile da ammettere una configurazione. Ad esempio, la stringa di connessione al database o il numero di corsi da visualizzare nell’elenco sono valori di configurazione che dovremmo tenere in una fonte esterna all’applicazione, come un file di testo. In questo modo, il nostro committente potrà modificare liberamente tali valori secondo le sue necessità, senza dover chiedere a noi sviluppatori di apportare modifiche al codice C# o di ricompilare l’applicazione.
ASP.NET Core può avvalersi di varie fonti di configurazione esterne all’applicazione, come ad esempio il file appsettings.json, in cui possiamo inserire valori di configurazione organizzati su più sezioni annidate.
In questo esempio, nella sezione ConnectionStrings si trova la chiave Default a cui è stato assegnato il valore Data Source=Data/MyCourse.db che rappresenta una stringa di connessione al database.
- {
- “ConnectionStrings”: {
- “Default”: “Data Source=Data/MyCourse.db”
- }
- }
Per leggere il valore dall’applicazione, riceviamo il servizio IConfiguration dal costruttore di un componente qualsiasi, compresa la classe Startup. Nel seguente esempio leggiamo il valore dal nostro servizio infrastrutturale SqliteDatabaseAccessor.
- public class SqliteDatabaseAccessor : IDatabaseAccessor
- {
- private readonly IConfiguration configuration;
- //Ricevo il servizio dal costruttore
- public SqliteDatabaseAccessor(IConfiguration configuration)
- {
- //Conservo il riferimento al servizio su un campo privato…
- this.configuration = configuration;
- }
- public async Task QueryAsync(FormattableString formattableQuery)
- {
- //…e da qui leggiamo il valore della chiave “Default” della sezione “ConnectionStrings”
- string connectionString = configuration.GetValue(“ConnectionStrings:Default”);
- //Oppure, dato che si tratta di un valore di tipo string potremmo scrivere più brevemente
- //string connectionString = configuration[“ConnectionStrings:Default”];
- //O ancora, dato che il valore si trova nella sezione “ConnectionStrings”:
- //string connectionString = configuration.GetConnectionString(“Default”);
- //TODO: Qui usiamo connectionString per collegarci al database
- }
- }
IL SERVIZIO IOPTIONSMONITOR<T>
Come abbiamo visto in questo esempio, al servizio IConfiguration dobbiamo fornire il percorso della chiave di configurazione, come ConnectionStrings:Default, in cui è stato usato il carattere : come separatore di nomi.
Questa tecnica può prestarsi a errori di digitazione che scopriremmo solo a runtime e perciò, per renderci più produttivi, ASP.NET Core offre anche un altro servizio chiamato IOptionsMonitor<T> che ci permette di accedere ai valori di configurazione in maniera fortemente tipizzata, così che ogni eventuale errore venga segnalato all’atto della compilazione.
Andiamo dunque a riscrivere l’esempio precedente come segue:
- public class SqliteDatabaseAccessor : IDatabaseAccessor
- {
- private readonly IOptionsMonitor<ConnectionStringsOptions> options;
- //Ricevo il servizio dal costruttore
- public SqliteDatabaseAccessor(IOptionsMonitor<ConnectionStringsOptions> options)
- {
- //Conservo il riferimento al servizio su un campo privato…
- this.options = options;
- }
- public async Task QueryAsync(FormattableString formattableQuery)
- {
- //…e da qui leggiamo la proprietà Default dell’oggetto di tipo ConnectionStringsOptions
- string connectionString = options.CurrentValue.Default;
- //TODO: Qui usiamo connectionString per collegarci al database
- }
- }
Nell’esempio che abbiamo appena visto, la ConnectionStringsOptions è una classe che dobbiamo creare noi e che possiamo chiamare come vogliamo. È importante che contenga delle proprietà aventi lo stesso nome di quelle trovate nella sezione di configurazione ConnectionStrings. Ecco un esempio di tale classe.
- public class ConnectionStringsOptions
- {
- //Possiede una proprietà Default di tipo string, proprio come nell’appsettings.json
- public string Default { get; set; }
- }
Per finire, dobbiamo istruire ASP.NET Core che deve riversare i valori di configurazione trovati nella sezione ConnectionStrings all’interno di un’istanza della nostra classe ConnectionStringsOptions. Andiamo dunque ad aggiungere la seguente riga di codice nel metodo ConfigureServices della classe Startup.
- //Qui usiamo il metodo GetSection del servizio IConfiguration
- //per ottenere il riferimento alla sezione ConnectionStrings
- service.Configure<ConnectionStringsOptions>(Configuration.GetSection(“ConnectionStrings”));
LE FONTI DI CONFIGURAZIONE
Il file appsettings.json è solo una delle fonti di configurazione di cui possiamo avvalerci. ASP.NET Core è già predisposto per sfruttarne altre; eccole in ordine di priorità.
- appsettings.NomeAmbiente.json, un file json in cui inseriamo la configurazione specifica che l’applicazione userà solo quando viene eseguita in un particolare ambiente (es. Development, Production, Staging, …);
- User secrets, che sono ideali per impostare una configurazione personalizzata per la nostra macchina di sviluppo. Dato che i valori non entrano nel repository GIT, ciascuno sviluppatore che collabora al progetto può avere la sua personalissima configurazione senza influenzare gli altri. Si impostano con il comando dotnet user-secrets set “Sezione:Chiave” “Valore”;
- Variabili ambiente, sono utili quando vogliamo impostare dei valori di configurazione che contengono informazioni sensibili, come username, password, chiavi API e così via. Proprio come gli user secrets, anche in questo caso i valori non entreranno nel repository GIT e perciò resteranno al sicuro sulla macchina che esegue l’applicazione. Ricorda: usa il doppio underscore __ anziché : come separatore di nomi nell’indicare il nome della variabile d’ambiente;
- Parametri da riga di comando, è la fonte più prioritaria e che perciò può ridefinire i valori impostati nelle precedenti fonti. Semplicemente, bisogna fornire i valori all’avvio dell’applicazione con il comando dotnet run –Sezione:Chiave=”Valore” oppure, se siamo già in produzione, dotnet MyCourse.dll –Sezione:Chiave=”Valore”;
Alcune fonti, come quelle basate su file di testo, sono aggiornabili a caldo. Vuol dire che, ad esempio, possiamo modificare un valore nel file appsettings.json senza che sia poi necessario riavviare l’applicazione. Il valore aggiornato verrà immediatamente reso disponibile dai servizi IConfiguration e IOptionsMonitor.
ESTENDERE IL SERVIZIO DI CONFIGURAZIONE
ASP.NET Core è molto estendibile e perciò supporta anche altre fonti di configurazione, addirittura create dallo sviluppatore. Se aggiungiamo il metodo ConfigureAppConfiguration nel punto in cui viene creato il web host, nella classe Program, possiamo personalizzare sia le fonti che il loro ordine di priorità.
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- CreateDefaultBuilder(args)
- .ConfigureAppConfiguration((context, builder) => {
- //Qui impostiamo le fonti di configurazione o ne cambiamo l’ordine di priorità
- })
- .UseStartup();
LINK AL CODICE SU GITHUB
Scaricare il codice della sezione12 o clonare il repository GITHUB per avere a disposizione tutte le sezioni nel tuo editor preferito.
Scrivi un commento