Generatori di configurazioni per ASP.NET
Di Stephen Molloy e Rick Anderson
I generatori di configurazioni forniscono un meccanismo moderno e agile per ASP.NET app per ottenere valori di configurazione da origini esterne.
Generatori di configurazioni:
- Sono disponibili in .NET Framework 4.7.1 e versioni successive.
- Fornire un meccanismo flessibile per la lettura dei valori di configurazione.
- Soddisfare alcune delle esigenze di base delle app durante lo spostamento in un contenitore e in un ambiente incentrato sul cloud.
- Può essere usato per migliorare la protezione dei dati di configurazione mediante il disegno da origini precedentemente non disponibili (ad esempio, Azure Key Vault e variabili di ambiente) nel sistema di configurazione .NET.
Uno scenario comune che può essere gestito dai generatori di configurazione consiste nel fornire un meccanismo di sostituzione chiave/valore di base per le sezioni di configurazione che seguono un modello chiave/valore. Il concetto di .NET Framework di ConfigurationBuilders non è limitato a sezioni o modelli di configurazione specifici. Tuttavia, molti dei generatori di configurazione in Microsoft.Configuration.ConfigurationBuilders
(github, NuGet) funzionano all'interno del modello chiave/valore.
Le impostazioni seguenti si applicano a tutti i generatori di configurazioni chiave/valore in Microsoft.Configuration.ConfigurationBuilders
.
I generatori di configurazione usano un'origine esterna di informazioni chiave/valore per popolare gli elementi chiave/valore selezionati del sistema di configurazione. In particolare, le <appSettings/>
sezioni e <connectionStrings/>
ricevono un trattamento speciale dai generatori di configurazione. I generatori funzionano in tre modalità:
Strict
- Modalità predefinita. In questa modalità, il generatore di configurazione opera solo su sezioni di configurazione note incentrate su chiave/valore.Strict
mode enumera ogni chiave nella sezione . Se viene trovata una chiave corrispondente nell'origine esterna:- I generatori di configurazione sostituiscono il valore nella sezione di configurazione risultante con il valore dell'origine esterna.
Greedy
- Questa modalità è strettamente correlata allaStrict
modalità. Anziché essere limitati alle chiavi già presenti nella configurazione originale:- I generatori di configurazione aggiungono tutte le coppie chiave/valore dall'origine esterna alla sezione di configurazione risultante.
Expand
- Opera sul codice XML non elaborato prima di essere analizzato in un oggetto sezione di configurazione. Può essere considerato come un'espansione di token in una stringa. Qualsiasi parte della stringa XML non elaborata che corrisponde al modello${token}
è un candidato per l'espansione del token. Se nell'origine esterna non viene trovato alcun valore corrispondente, il token non viene modificato. I generatori in questa modalità non sono limitati alle<appSettings/>
sezioni e<connectionStrings/>
.
Il markup seguente da web.config abilita EnvironmentConfigBuilder in Strict
modalità:
<configuration>
<configSections>
<section name="configBuilders"
type="System.Configuration.ConfigurationBuildersSection,
System.Configuration, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="MyEnvironment"
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment,
Version=1.0.0.0, Culture=neutral" />
</builders>
</configBuilders>
<appSettings configBuilders="MyEnvironment">
<add key="ServiceID" value="ServiceID value from web.config" />
<add key="ServiceKey" value="ServiceKey value from web.config" />
</appSettings>
<connectionStrings configBuilders="MyEnvironment">
<add name="default" connectionString="Data Source=web.config/mydb.db" />
</connectionStrings>
Il codice seguente legge <appSettings/>
e <connectionStrings/>
illustrato nel file web.config precedente:
using System;
using System.Configuration;
using System.Web.UI;
namespace MyConfigBuilders
{
public partial class About : Page
{
public string ServiceID { get; set; }
public string ServiceKey { get; set; }
public string ConString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
ServiceID = ConfigurationManager.AppSettings["ServiceID"];
ServiceKey = ConfigurationManager.AppSettings["ServiceKey"];
ConString = ConfigurationManager.ConnectionStrings["default"]
?.ConnectionString;
}
}
}
Il codice precedente imposta i valori della proprietà su:
- I valori nel file web.config se le chiavi non sono impostate nelle variabili di ambiente.
- Valori della variabile di ambiente, se impostata.
Ad esempio, ServiceID
conterrà:
- "Valore ServiceID da web.config", se la variabile di ambiente non è impostata
ServiceID
. - Valore della
ServiceID
variabile di ambiente, se impostato.
L'immagine seguente mostra le <appSettings/>
chiavi/valori del file web.config precedente impostato nell'editor dell'ambiente:
Nota: potrebbe essere necessario uscire e riavviare Visual Studio per visualizzare le modifiche nelle variabili di ambiente.
I prefissi chiave possono semplificare l'impostazione delle chiavi perché:
- La configurazione di .NET Framework è complessa e annidata.
- Le origini chiave/valore esterne sono in genere di base e flat per natura. Ad esempio, le variabili di ambiente non sono annidate.
Usare uno degli approcci seguenti per inserire sia che <appSettings/>
<connectionStrings/>
nella configurazione tramite variabili di ambiente:
- Con nella
EnvironmentConfigBuilder
modalità predefinitaStrict
e i nomi di chiave appropriati nel file di configurazione. Il codice e il markup precedenti accettano questo approccio. Con questo approccio non è possibile avere chiavi denominate in modo identico sia<appSettings/>
in che<connectionStrings/>
in . - Usare due
EnvironmentConfigBuilder
s inGreedy
modalità con prefissi distinti estripPrefix
. Con questo approccio, l'app può leggere<appSettings/>
e<connectionStrings/>
senza dover aggiornare il file di configurazione. Nella sezione successiva, stripPrefix, viene illustrato come eseguire questa operazione. - Usare due
EnvironmentConfigBuilder
s inGreedy
modalità con prefissi distinti. Con questo approccio non è possibile avere nomi di chiave duplicati perché i nomi delle chiavi devono essere diversi per prefisso. Ad esempio:
<configuration>
<configSections>
<section name="configBuilders"
type="System.Configuration.ConfigurationBuildersSection,
System.Configuration, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="AS_Environment" mode="Greedy" prefix="AppSetting_"
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment" />
<add name="CS_Environment" mode="Greedy" prefix="ConnStr_"
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment" />
</builders>
</configBuilders>
<appSettings configBuilders="AS_Environment">
<add key="AppSetting_ServiceID" value="ServiceID value from web.config" />
<add key="AppSetting_default" value="AppSetting_default value from web.config" />
</appSettings>
<connectionStrings configBuilders="CS_Environment">
<add name="ConnStr_default" connectionString="Data Source=web.config/mydb.db" />
</connectionStrings>
Con il markup precedente, è possibile usare la stessa origine chiave/valore flat per popolare la configurazione per due sezioni diverse.
L'immagine seguente mostra i <appSettings/>
valori e e <connectionStrings/>
del file web.config precedente impostato nell'editor dell'ambiente:
Il codice seguente legge i <appSettings/>
valori e e <connectionStrings/>
contenuti nel file web.config precedente:
public partial class Contact : Page
{
public string ServiceID { get; set; }
public string AppSetting_default { get; set; }
public string ConString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
ServiceID = ConfigurationManager.AppSettings["AppSetting_ServiceID"];
AppSetting_default = ConfigurationManager.AppSettings["AppSetting_default"];
ConString = ConfigurationManager.ConnectionStrings["ConnStr_default"]
?.ConnectionString;
}
}
Il codice precedente imposta i valori della proprietà su:
- I valori nel file web.config se le chiavi non sono impostate nelle variabili di ambiente.
- Valori della variabile di ambiente, se impostata.
Ad esempio, usando il file web.config precedente, le chiavi/valori nell'immagine dell'editor dell'ambiente precedente e il codice precedente, vengono impostati i valori seguenti:
Chiave | valore |
---|---|
AppSetting_ServiceID | AppSetting_ServiceID da variabili di env |
AppSetting_default | AppSetting_default valore da env |
ConnStr_default | ConnStr_default val da env |
stripPrefix
: valore booleano, il valore predefinito è false
.
Il markup XML precedente separa le impostazioni dell'app dalle stringa di connessione, ma richiede che tutte le chiavi nel file web.config usino il prefisso specificato. Ad esempio, il prefisso AppSetting
deve essere aggiunto alla ServiceID
chiave ("AppSetting_ServiceID"). Con stripPrefix
, il prefisso non viene usato nel file web.config . Il prefisso è obbligatorio nell'origine del generatore di configurazione, ad esempio nell'ambiente. La maggior parte degli sviluppatori userà stripPrefix
.
Le applicazioni in genere esegnino il prefisso. Il codice web.config seguente rimuove il prefisso:
<configuration>
<configSections>
<section name="configBuilders"
type="System.Configuration.ConfigurationBuildersSection,
System.Configuration, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="AS_Environment" mode="Greedy" prefix="AppSetting_"
stripPrefix="true"
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment,
Version=1.0.0.0, Culture=neutral" />
<add name="CS_Environment" mode="Greedy" prefix="ConnStr_"
stripPrefix="true"
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment,
Version=1.0.0.0, Culture=neutral" />
</builders>
</configBuilders>
<appSettings configBuilders="AS_Environment">
<add key="ServiceID" value="ServiceID value from web.config" />
<add key="default" value="AppSetting_default value from web.config" />
</appSettings>
<connectionStrings configBuilders="CS_Environment">
<add name="default" connectionString="Data Source=web.config/mydb.db" />
</connectionStrings>
Nel file web.config precedente la default
chiave si trova sia <appSettings/>
in che <connectionStrings/>
in .
L'immagine seguente mostra i <appSettings/>
valori e e <connectionStrings/>
del file web.config precedente impostato nell'editor dell'ambiente:
Il codice seguente legge i <appSettings/>
valori e e <connectionStrings/>
contenuti nel file web.config precedente:
public partial class About2 : Page
{
public string ServiceID { get; set; }
public string AppSetting_default { get; set; }
public string ConString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
ServiceID = ConfigurationManager.AppSettings["ServiceID"];
AppSetting_default = ConfigurationManager.AppSettings["default"];
ConString = ConfigurationManager.ConnectionStrings["default"]
?.ConnectionString;
}
}
Il codice precedente imposta i valori della proprietà su:
- I valori nel file web.config se le chiavi non sono impostate nelle variabili di ambiente.
- Valori della variabile di ambiente, se impostata.
Ad esempio, usando il file web.config precedente, le chiavi/valori nell'immagine dell'editor dell'ambiente precedente e il codice precedente, vengono impostati i valori seguenti:
Chiave | valore |
---|---|
ServiceID | AppSetting_ServiceID da variabili di env |
impostazione predefinita | AppSetting_default valore da env |
impostazione predefinita | ConnStr_default val da env |
tokenPattern
: stringa, per impostazione predefinita @"\$\{(\w+)\}"
Il Expand
comportamento dei generatori cerca nel codice XML non elaborato i token simili ${token}
a . La ricerca viene eseguita con l'espressione @"\$\{(\w+)\}"
regolare predefinita . Il set di caratteri corrispondenti \w
è più rigoroso di XML e molte origini di configurazione consentite. Usare tokenPattern
quando sono necessari più @"\$\{(\w+)\}"
caratteri nel nome del token.
tokenPattern
:Corda:
- Consente agli sviluppatori di modificare l'espressione regolare usata per la corrispondenza dei token.
- Non viene eseguita alcuna convalida per assicurarsi che sia un'espressione regolare ben formata e non pericolosa.
- Deve contenere un gruppo di acquisizione. L'intera espressione regolare deve corrispondere all'intero token. La prima acquisizione deve essere il nome del token da cercare nell'origine di configurazione.
<add name="Environment"
[mode|prefix|stripPrefix|tokenPattern]
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment" />
- È il più semplice dei generatori di configurazione.
- Legge i valori dall'ambiente.
- Non sono disponibili opzioni di configurazione aggiuntive.
- Il valore dell'attributo
name
è arbitrario.
Nota: in un ambiente contenitore Windows, le variabili impostate in fase di esecuzione vengono inserite solo nell'ambiente del processo EntryPoint. Le app eseguite come servizio o un processo non EntryPoint non prelevano queste variabili, a meno che non vengano inserite in altro modo tramite un meccanismo nel contenitore. Per i contenitori basati su IIS/ASP.NET, la versione corrente di ServiceMonitor.exe gestisce questa opzione solo in DefaultAppPool. Altre varianti di contenitore basate su Windows potrebbero dover sviluppare il proprio meccanismo di inserimento per i processi non EntryPoint.
Avviso
Non archiviare mai password, stringa di connessione sensibili o altri dati sensibili nel codice sorgente. I segreti di produzione non devono essere usati per lo sviluppo o il test.
<add name="UserSecrets"
[mode|prefix|stripPrefix|tokenPattern]
(userSecretsId="{secret string, typically a GUID}" | userSecretsFile="~\secrets.file")
[optional="true"]
type="Microsoft.Configuration.ConfigurationBuilders.UserSecretsConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.UserSecrets" />
Nel codice XML precedente, il userSecretsFile
percorso può usare ~/
o ~\
. Ad esempio, il percorso può essere scritto come userSecretsFile="~/secrets.file
. Per altre informazioni, vedere la classe ConfigurationBuilders Utils .
Questo generatore di configurazione offre una funzionalità simile a ASP.NET Core Secret Manager.
È possibile usare UserSecretsConfigBuilder nei progetti .NET Framework, ma è necessario specificare un file di segreti. In alternativa, è possibile definire la UserSecretsId
proprietà nel file di progetto e creare il file dei segreti non elaborati nel percorso corretto per la lettura. Per evitare dipendenze esterne dal progetto, il file segreto è formattato in formato XML. La formattazione XML è un dettaglio di implementazione e il formato non deve essere basato su . Se è necessario condividere un file secrets.json con i progetti .NET Core, è consigliabile usare SimpleJsonConfigBuilder. Anche il SimpleJsonConfigBuilder
formato per .NET Core deve essere considerato un dettaglio di implementazione soggetto a modifiche.
Attributi di configurazione per UserSecretsConfigBuilder
:
userSecretsId
- Questo è il metodo preferito per identificare un file di segreti XML. Funziona in modo simile a .NET Core, che usa unaUserSecretsId
proprietà del progetto per archiviare questo identificatore. La stringa deve essere univoca, non deve essere un GUID. Con questo attributo, l'aspettoUserSecretsConfigBuilder
in un percorso locale noto (%APPDATA%\Microsoft\UserSecrets\<UserSecrets Id>\secrets.xml
) per un file di segreti appartenente a questo identificatore.userSecretsFile
- Attributo facoltativo che specifica il file contenente i segreti. Il~
carattere può essere usato all'inizio per fare riferimento alla radice dell'applicazione. Questo attributo o l'attributouserSecretsId
è obbligatorio. Se vengono specificati entrambi,userSecretsFile
ha la precedenza.optional
: valore booleano, valoretrue
predefinito: impedisce un'eccezione se non è possibile trovare il file dei segreti.- Il valore dell'attributo
name
è arbitrario.
Il file dei segreti ha il formato seguente:
<?xml version="1.0" encoding="utf-8" ?>
<root>
<secrets ver="1.0">
<secret name="secret key name" value="secret value" />
</secrets>
</root>
<add name="AzureKeyVault"
[mode|prefix|stripPrefix|tokenPattern]
(vaultName="MyVaultName" |
uri="https:/MyVaultName.vault.azure.net")
[version="secrets version"]
[preloadSecretNames="true"]
type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Azure" />
AzureKeyVaultConfigBuilder legge i valori archiviati nell'insieme di credenziali delle chiavi di Azure.
vaultName
è obbligatorio (il nome dell'insieme di credenziali o un URI per l'insieme di credenziali). Gli altri attributi consentono di controllare l'insieme di credenziali a cui connettersi, ma sono necessari solo se l'applicazione non è in esecuzione in un ambiente che funziona con Microsoft.Azure.Services.AppAuthentication
. La libreria di autenticazione dei servizi di Azure viene usata per raccogliere automaticamente le informazioni di connessione dall'ambiente di esecuzione, se possibile. È possibile eseguire l'override della selezione automatica delle informazioni di connessione fornendo un stringa di connessione.
vaultName
- Obbligatorio seuri
non specificato. Specifica il nome dell'insieme di credenziali nella sottoscrizione di Azure da cui leggere coppie chiave/valore.uri
- Si connette ad altri provider di Key Vault con il valore specificatouri
. Se non specificato, Azure (vaultName
) è il provider dell'insieme di credenziali.version
- Azure Key Vault offre una funzionalità di controllo delle versioni per i segreti. Seversion
viene specificato, il generatore recupera solo i segreti corrispondenti a questa versione.preloadSecretNames
- Per impostazione predefinita, questo generatore esegue una query su tutti i nomi di chiave nell'insieme di credenziali delle chiavi quando viene inizializzato. Per impedire la lettura di tutti i valori di chiave, impostare questo attributo sufalse
. L'impostazione di questa opzione sufalse
legge i segreti uno alla volta. La lettura dei segreti uno alla volta può essere utile se l'insieme di credenziali consente l'accesso "Get" ma non "List". Nota: quando si usaGreedy
la modalità,preloadSecretNames
deve esseretrue
(impostazione predefinita).
<add name="KeyPerFile"
[mode|prefix|stripPrefix|tokenPattern]
(directoryPath="PathToSourceDirectory")
[ignorePrefix="ignore."]
[keyDelimiter=":"]
[optional="false"]
type="Microsoft.Configuration.ConfigurationBuilders.KeyPerFileConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.KeyPerFile" />
KeyPerFileConfigBuilder è un generatore di configurazione di base che usa i file di una directory come origine dei valori. Il nome di un file è la chiave e il contenuto è il valore. Questo generatore di configurazione può essere utile quando viene eseguito in un ambiente contenitore orchestrato. I sistemi come Docker Swarm e Kubernetes forniscono secrets
ai contenitori windows orchestrati in questo modo chiave per file.
Dettagli attributo:
directoryPath
- Obbligatorio. Specifica un percorso in cui cercare i valori. Per impostazione predefinita, Docker per i segreti di Windows vengono archiviati nella directory C:\ProgramData\Docker\secrets .ignorePrefix
- I file che iniziano con questo prefisso vengono esclusi. Il valore predefinito è "ignore".keyDelimiter
- Il valore predefinito ènull
. Se specificato, il generatore di configurazione attraversa più livelli della directory, creando nomi di chiave con questo delimitatore. Se questo valore ènull
, il generatore di configurazione esamina solo il livello superiore della directory.optional
- Il valore predefinito èfalse
. Specifica se il generatore di configurazione deve causare errori se la directory di origine non esiste.
Avviso
Non archiviare mai password, stringa di connessione sensibili o altri dati sensibili nel codice sorgente. I segreti di produzione non devono essere usati per lo sviluppo o il test.
<add name="SimpleJson"
[mode|prefix|stripPrefix|tokenPattern]
jsonFile="~\config.json"
[optional="true"]
[jsonMode="(Flat|Sectional)"]
type="Microsoft.Configuration.ConfigurationBuilders.SimpleJsonConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Json" />
I progetti .NET Core usano spesso file JSON per la configurazione. Il generatore SimpleJsonConfigBuilder consente l'uso di file JSON .NET Core in .NET Framework. Questo generatore di configurazione fornisce un mapping di base da un'origine chiave/valore flat in aree chiave/valore specifiche della configurazione di .NET Framework. Questo generatore di configurazione non fornisce configurazioni gerarchiche. Il file di backup JSON è simile a un dizionario, non a un oggetto gerarchico complesso. È possibile usare un file gerarchico a più livelli. Questo provider flatten
aggiunge il nome della proprietà a ogni livello usando :
come delimitatore.
Dettagli attributo:
jsonFile
- Obbligatorio. Specifica il file JSON da cui leggere. Il~
carattere può essere usato all'inizio per fare riferimento alla radice dell'app.optional
- Valore booleano, il valore predefinito ètrue
. Impedisce la generazione di eccezioni se non è possibile trovare il file JSON.jsonMode
-[Flat|Sectional]
.Flat
è l'impostazione predefinita. QuandojsonMode
èFlat
, il file JSON è un'unica origine chiave/valore flat.EnvironmentConfigBuilder
eAzureKeyVaultConfigBuilder
sono anche singole origini chiave/valore flat. Quando èSimpleJsonConfigBuilder
configurato inSectional
modalità :- Il file JSON è concettualmente diviso solo al livello superiore in più dizionari.
- Ogni dizionario viene applicato solo alla sezione di configurazione corrispondente al nome della proprietà di primo livello associato. Ad esempio:
{
"appSettings" : {
"setting1" : "value1",
"setting2" : "value2",
"complex" : {
"setting1" : "complex:value1",
"setting2" : "complex:value2",
}
}
}
Vedere ConfigurationBuilders Order of Execution (Ordine di esecuzione di ConfigurationBuilders) nel repository GitHub aspnet/MicrosoftConfigurationBuilders .
Se i generatori di configurazione non soddisfano le proprie esigenze, è possibile scriverne uno personalizzato. La KeyValueConfigBuilder
classe base gestisce le modalità di sostituzione e la maggior parte dei problemi di prefisso. Un progetto di implementazione deve solo:
- Ereditare dalla classe base e implementare un'origine di base di coppie chiave/valore tramite
GetValue
eGetAllValues
: - Aggiungere Microsoft.Configuration.ConfigurationBuilders.Base al progetto.
using Microsoft.Configuration.ConfigurationBuilders;
using System.Collections.Generic;
public class MyCustomConfigBuilder : KeyValueConfigBuilder
{
public override string GetValue(string key)
{
// Key lookup should be case-insensitive, because most key/value collections in
// .NET Framework config sections are case-insensitive.
return "Value for given key, or null.";
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix)
{
// Populate the return collection.
return new Dictionary<string, string>() { { "one", "1" }, { "two", "2" } };
}
}
La KeyValueConfigBuilder
classe base fornisce gran parte del comportamento di lavoro e coerente tra i generatori di configurazioni chiave/valore.