Construtores de configuração para ASP.NET
Por Stephen Molloy e Rick Anderson
Os criadores de configuração fornecem um mecanismo moderno e ágil para que ASP.NET aplicativos obtenham valores de configuração de fontes externas.
Construtores de configuração:
- Estão disponíveis no .NET Framework 4.7.1 e posterior.
- Forneça um mecanismo flexível para ler valores de configuração.
- Atenda a algumas das necessidades básicas dos aplicativos à medida que eles se movem para um ambiente focado em contêiner e nuvem.
- Pode ser usado para melhorar a proteção de dados de configuração extraindo de fontes anteriormente indisponíveis (por exemplo, Azure Key Vault e variáveis de ambiente) no sistema de configuração do .NET.
Um cenário comum que pode ser tratado por construtores de configuração é fornecer um mecanismo básico de substituição de chave/valor para seções de configuração que seguem um padrão de chave/valor. O conceito do .NET Framework de ConfigurationBuilders não se limita a seções ou padrões de configuração específicos. No entanto, muitos dos construtores de configuração em Microsoft.Configuration.ConfigurationBuilders
(github, NuGet) funcionam dentro do padrão de chave/valor.
As configurações a seguir se aplicam a todos os construtores de configuração de chave/valor no Microsoft.Configuration.ConfigurationBuilders
.
Os construtores de configuração usam uma fonte externa de informações de chave/valor para preencher os elementos de chave/valor selecionados do sistema de configuração. Especificamente, as <appSettings/>
seções e <connectionStrings/>
recebem tratamento especial dos construtores de configuração. Os construtores funcionam em três modos:
Strict
- O modo padrão. Nesse modo, o construtor de configuração opera apenas em seções de configuração centradas em chave/valor conhecidas.Strict
mode enumera cada chave na seção. Se uma chave correspondente for encontrada na fonte externa:- Os construtores de configuração substituem o valor na seção de configuração resultante pelo valor da fonte externa.
Greedy
- Este modo está intimamente relacionado aoStrict
modo. Em vez de se limitar a chaves que já existem na configuração original:- Os construtores de configuração adicionam todos os pares de chave/valor da fonte externa na seção de configuração resultante.
Expand
- Opera no XML bruto antes de ser analisado em um objeto de seção de configuração. Pode ser pensado como uma expansão de tokens em uma string. Qualquer parte da cadeia de caracteres XML bruta que corresponda ao padrão${token}
é candidata à expansão do token. Se nenhum valor correspondente for encontrado na fonte externa, o token não será alterado. Os construtores neste modo não estão limitados às<appSettings/>
seções e<connectionStrings/>
.
A seguinte marcação de web.config habilita o EnvironmentConfigBuilder no Strict
modo:
<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>
O código a seguir lê o <appSettings/>
e <connectionStrings/>
mostrado no arquivo web.config anterior:
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;
}
}
}
O código anterior definirá os valores de propriedade como:
- Os valores no arquivo web.config se as chaves não estiverem definidas em variáveis de ambiente.
- Os valores da variável de ambiente, se definidos.
Por exemplo, ServiceID
conterá:
- "ServiceID value from web.config", se a variável
ServiceID
de ambiente não estiver definida. - O valor da variável de
ServiceID
ambiente, se definido.
A imagem a seguir mostra as <appSettings/>
chaves/valores do arquivo web.config anterior definido no editor de ambiente:
Observação: talvez seja necessário sair e reiniciar o Visual Studio para ver as alterações nas variáveis de ambiente.
Os prefixos de chave podem simplificar a configuração de chaves porque:
- A configuração do .NET Framework é complexa e aninhada.
- As fontes externas de chave/valor são geralmente básicas e planas por natureza. Por exemplo, as variáveis de ambiente não são aninhadas.
Use qualquer uma das seguintes abordagens para injetar e <appSettings/>
<connectionStrings/>
na configuração por meio de variáveis de ambiente:
- Com o
EnvironmentConfigBuilder
no modo padrãoStrict
e os nomes de chave apropriados no arquivo de configuração. O código e a marcação anteriores usam essa abordagem. Usando essa abordagem, você não pode ter chaves com nomes idênticos em ambos e<appSettings/>
<connectionStrings/>
. - Use dois
EnvironmentConfigBuilder
s noGreedy
modo com prefixos distintos estripPrefix
. Com essa abordagem, o aplicativo pode ler<appSettings/>
e<connectionStrings/>
sem precisar atualizar o arquivo de configuração. A próxima seção, stripPrefix, mostra como fazer isso. - Use dois
EnvironmentConfigBuilder
s noGreedy
modo com prefixos distintos. Com essa abordagem, você não pode ter nomes de chave duplicados, pois os nomes de chave devem ser diferentes por prefixo. Por exemplo:
<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>
Com a marcação anterior, a mesma fonte de chave/valor simples pode ser usada para preencher a configuração de duas seções diferentes.
A imagem a seguir mostra as <appSettings/>
chaves/valores e <connectionStrings/>
do arquivo web.config anterior definido no editor de ambiente:
O código a seguir lê as <appSettings/>
chaves/valores e <connectionStrings/>
contidos no arquivo web.config anterior:
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;
}
}
O código anterior definirá os valores de propriedade como:
- Os valores no arquivo web.config se as chaves não estiverem definidas em variáveis de ambiente.
- Os valores da variável de ambiente, se definidos.
Por exemplo, usando o arquivo web.config anterior, as chaves/valores na imagem anterior do editor de ambiente e o código anterior, os seguintes valores são definidos:
Chave | Valor |
---|---|
AppSetting_ServiceID | AppSetting_ServiceID de variáveis env |
AppSetting_default | AppSetting_default valor do ambiente |
ConnStr_default | ConnStr_default val de env |
stripPrefix
: booleano, o padrão é false
.
A marcação XML anterior separa as configurações do aplicativo das cadeias de conexão, mas requer que todas as chaves no arquivo web.config usem o prefixo especificado. Por exemplo, o prefixo AppSetting
ServiceID
deve ser adicionado à chave ("AppSetting_ServiceID"). Com stripPrefix
, o prefixo não é usado no arquivo web.config . O prefixo é necessário na origem do construtor de configuração (por exemplo, no ambiente). Prevemos que a maioria dos desenvolvedores usará stripPrefix
o .
Os aplicativos normalmente removem o prefixo. O web.config a seguir remove o prefixo:
<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>
No arquivo web.config anterior, a default
chave está no <appSettings/>
arquivo e <connectionStrings/>
.
A imagem a seguir mostra as <appSettings/>
chaves/valores e <connectionStrings/>
do arquivo web.config anterior definido no editor de ambiente:
O código a seguir lê as <appSettings/>
chaves/valores e <connectionStrings/>
contidos no arquivo web.config anterior:
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;
}
}
O código anterior definirá os valores de propriedade como:
- Os valores no arquivo web.config se as chaves não estiverem definidas em variáveis de ambiente.
- Os valores da variável de ambiente, se definidos.
Por exemplo, usando o arquivo web.config anterior, as chaves/valores na imagem anterior do editor de ambiente e o código anterior, os seguintes valores são definidos:
Chave | Valor |
---|---|
ServiceID | AppSetting_ServiceID de variáveis env |
padrão | AppSetting_default valor do ambiente |
padrão | ConnStr_default val de env |
tokenPattern
: String, o padrão é @"\$\{(\w+)\}"
O Expand
comportamento dos construtores pesquisa o XML bruto em busca de tokens que se pareçam com ${token}
. A pesquisa é feita com a expressão @"\$\{(\w+)\}"
regular padrão . O conjunto de caracteres que corresponde \w
é mais rigoroso do que o XML e muitas fontes de configuração permitem. Use tokenPattern
quando mais caracteres do que @"\$\{(\w+)\}"
o necessário no nome do token.
tokenPattern
:Corda:
- Permite que os desenvolvedores alterem o regex usado para correspondência de token.
- Nenhuma validação é feita para garantir que seja um regex bem formado e não perigoso.
- Ele deve conter um grupo de captura. Todo o regex deve corresponder ao token inteiro. A primeira captura deve ser o nome do token a ser pesquisado na fonte de configuração.
<add name="Environment"
[mode|prefix|stripPrefix|tokenPattern]
type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Environment" />
- É o mais simples dos construtores de configuração.
- Lê valores do ambiente.
- Não tem nenhuma opção de configuração adicional.
- O
name
valor do atributo é arbitrário.
Nota: Em um ambiente de contêiner do Windows, as variáveis definidas no tempo de execução são injetadas apenas no ambiente de processo EntryPoint. Os aplicativos executados como um serviço ou um processo que não é do EntryPoint não selecionam essas variáveis, a menos que sejam injetadas por meio de um mecanismo no contêiner. Para contêineres baseados em ASP.NET do IIS/, a versão atual do ServiceMonitor.exe lida com isso somente no DefaultAppPool. Outras variantes de contêiner baseadas em Windows podem precisar desenvolver seu próprio mecanismo de injeção para processos que não são do EntryPoint.
Aviso
Nunca armazene senhas, cadeias de conexão confidenciais ou outros dados confidenciais no código-fonte. Os segredos de produção não devem ser usados para desenvolvimento ou teste.
<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" />
No XML anterior, o userSecretsFile
caminho pode usar use ~/
ou ~\
. Por exemplo, o caminho pode ser escrito como userSecretsFile="~/secrets.file
. Consulte a classe ConfigurationBuilders Utils para obter mais informações.
Esse construtor de configuração fornece um recurso semelhante ao ASP.NET Core Secret Manager.
O UserSecretsConfigBuilder pode ser usado em projetos do .NET Framework, mas um arquivo de segredos deve ser especificado. Como alternativa, você pode definir a UserSecretsId
propriedade no arquivo de projeto e criar o arquivo de segredos brutos no local correto para leitura. Para manter as dependências externas fora do seu projeto, o arquivo secreto é formatado em XML. A formatação XML é um detalhe de implementação e o formato não deve ser confiável. Se você precisar compartilhar um arquivo secrets.json com projetos do .NET Core, considere usar o SimpleJsonConfigBuilder. O SimpleJsonConfigBuilder
formato do .NET Core também deve ser considerado um detalhe de implementação sujeito a alterações.
Atributos de configuração para UserSecretsConfigBuilder
:
userSecretsId
- Este é o método preferencial para identificar um arquivo de segredos XML. Ele funciona de forma semelhante ao .NET Core, que usa uma propriedade deUserSecretsId
projeto para armazenar esse identificador. A cadeia de caracteres deve ser exclusiva, não precisa ser um GUID. Com esse atributo, procuramosUserSecretsConfigBuilder
em um local conhecido (%APPDATA%\Microsoft\UserSecrets\<UserSecrets Id>\secrets.xml
) um arquivo de segredos pertencente a esse identificador.userSecretsFile
- Um atributo opcional que especifica o arquivo que contém os segredos. O~
caractere pode ser usado no início para fazer referência à raiz do aplicativo. Esse atributo ou ouserSecretsId
atributo é necessário. Se ambos forem especificados,userSecretsFile
terá precedência.optional
: booleano, valortrue
padrão - Impede uma exceção se o arquivo de segredos não puder ser encontrado.- O
name
valor do atributo é arbitrário.
O arquivo de segredos tem o seguinte formato:
<?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" />
O AzureKeyVaultConfigBuilder lê valores armazenados no Azure Key Vault.
vaultName
é necessário (o nome do vault ou um URI para o vault). Os outros atributos permitem o controle sobre a qual vault se conectar, mas só são necessários se o aplicativo não estiver sendo executado em um ambiente que funcione com Microsoft.Azure.Services.AppAuthentication
o . A biblioteca de Autenticação de Serviços do Azure é usada para coletar automaticamente informações de conexão do ambiente de execução, se possível. Você pode substituir automaticamente a coleta de informações de conexão fornecendo uma cadeia de conexão.
vaultName
- Obrigatório seuri
não for fornecido. Especifica o nome do cofre em sua assinatura do Azure a partir do qual ler pares chave/valor.uri
- Conecta-se a outros provedores do Key Vault com o valor especificadouri
. Se não for especificado, Azure (vaultName
) será o provedor do cofre.version
- O Azure Key Vault fornece um recurso de controle de versão para segredos. Seversion
for especificado, o construtor recuperará apenas os segredos correspondentes a essa versão.preloadSecretNames
- Por padrão, esse construtor consulta todos os nomes de chave no cofre de chaves quando ele é inicializado. Para impedir a leitura de todos os valores de chave, defina esse atributo comofalse
. Definir isso parafalse
ler os segredos um de cada vez. Ler segredos um de cada vez pode ser útil se o cofre permitir acesso "Obter", mas não acesso "Lista". Nota: Ao usarGreedy
o modo,preloadSecretNames
deve sertrue
(o padrão).
<add name="KeyPerFile"
[mode|prefix|stripPrefix|tokenPattern]
(directoryPath="PathToSourceDirectory")
[ignorePrefix="ignore."]
[keyDelimiter=":"]
[optional="false"]
type="Microsoft.Configuration.ConfigurationBuilders.KeyPerFileConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.KeyPerFile" />
KeyPerFileConfigBuilder é um construtor de configuração básica que usa os arquivos de um diretório como fonte de valores. O nome de um arquivo é a chave e o conteúdo é o valor. Esse construtor de configuração pode ser útil ao ser executado em um ambiente de contêiner orquestrado. Sistemas como o Docker Swarm e o Kubernetes fornecem secrets
aos contêineres do Windows orquestrados dessa maneira de chave por arquivo.
Detalhes do atributo:
directoryPath
- Obrigatório. Especifica um caminho para procurar valores. Os segredos do Docker para Windows são armazenados no diretório C:\ProgramData\Docker\secrets por padrão.ignorePrefix
- Os arquivos que começam com esse prefixo são excluídos. O padrão é "ignorar".keyDelimiter
- O valor padrão énull
. Se especificado, o construtor de configuração percorre vários níveis do diretório, criando nomes de chave com esse delimitador. Se esse valor fornull
, o construtor de configuração examinará apenas o nível superior do diretório.optional
- O valor padrão éfalse
. Especifica se o construtor de configuração deve causar erros se o diretório de origem não existir.
Aviso
Nunca armazene senhas, cadeias de conexão confidenciais ou outros dados confidenciais no código-fonte. Os segredos de produção não devem ser usados para desenvolvimento ou teste.
<add name="SimpleJson"
[mode|prefix|stripPrefix|tokenPattern]
jsonFile="~\config.json"
[optional="true"]
[jsonMode="(Flat|Sectional)"]
type="Microsoft.Configuration.ConfigurationBuilders.SimpleJsonConfigBuilder,
Microsoft.Configuration.ConfigurationBuilders.Json" />
Os projetos do .NET Core frequentemente usam arquivos JSON para configuração. O construtor SimpleJsonConfigBuilder permite que arquivos JSON do .NET Core sejam usados no .NET Framework. Esse construtor de configuração fornece um mapeamento básico de uma fonte de chave/valor simples para áreas específicas de chave/valor da configuração do .NET Framework. Esse construtor de configuração não fornece configurações hierárquicas. O arquivo de backup JSON é semelhante a um dicionário, não a um objeto hierárquico complexo. Um arquivo hierárquico de vários níveis pode ser usado. Esse provedor flatten
é a profundidade acrescentando o nome da propriedade em cada nível usando :
como um delimitador.
Detalhes do atributo:
jsonFile
- Obrigatório. Especifica o arquivo JSON do qual ler. O~
caractere pode ser usado no início para fazer referência à raiz do aplicativo.optional
- Booleano, o valor padrão étrue
. Impede o lançamento de exceções se o arquivo JSON não puder ser encontrado.jsonMode
-[Flat|Sectional]
.Flat
é o padrão. QuandojsonMode
éFlat
, o arquivo JSON é uma única fonte de chave/valor simples. OsEnvironmentConfigBuilder
eAzureKeyVaultConfigBuilder
também são fontes únicas de chave/valor simples. Quando oSimpleJsonConfigBuilder
está configurado noSectional
modo:- O arquivo JSON é conceitualmente dividido apenas no nível superior em vários dicionários.
- Cada um dos dicionários é aplicado apenas à seção de configuração que corresponde ao nome da propriedade de nível superior anexado a eles. Por exemplo:
{
"appSettings" : {
"setting1" : "value1",
"setting2" : "value2",
"complex" : {
"setting1" : "complex:value1",
"setting2" : "complex:value2",
}
}
}
Consulte Ordem de execução de ConfigurationBuilders no repositório GitHub aspnet/MicrosoftConfigurationBuilders .
Se os criadores de configuração não atenderem às suas necessidades, você poderá escrever um personalizado. A KeyValueConfigBuilder
classe base lida com modos de substituição e a maioria das preocupações de prefixo. Um projeto de execução precisa apenas:
- Herde da classe base e implemente uma fonte básica de pares chave/valor por meio do
GetValue
eGetAllValues
: - Adicione o Microsoft.Configuration.ConfigurationBuilders.Base ao projeto.
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" } };
}
}
A KeyValueConfigBuilder
classe base fornece grande parte do trabalho e do comportamento consistente entre os construtores de configuração de chave/valor.