Construtores de configuração para ASP.NET

Por Stephen Molloy e Rick Anderson

Os construtores de configuração fornecem um mecanismo moderno e ágil para 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.
  • Resolva algumas das necessidades básicas dos aplicativos à medida que eles se movem para um ambiente focado em contêiner e na nuvem.
  • Pode ser usado para melhorar a proteção de dados de configuração extraindo de fontes anteriormente indisponíveis (por exemplo, variáveis de ambiente e Key Vault do Azure) no sistema de configuração do .NET.

Construtores de configuração de chave/valor

Um cenário comum que pode ser tratado pelos 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 .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 no Microsoft.Configuration.ConfigurationBuilders (github, NuGet) funcionam dentro do padrão de chave/valor.

Definições de construtores de configuraçã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.

Modo

Os construtores de configuração usam uma fonte externa de informações de chave/valor para preencher 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 conhecidas centradas em chave/valor. Strict mode enumera cada chave na seção . Se uma chave correspondente for encontrada na origem externa:

    • Os construtores de configuração substituem o valor na seção de configuração resultante pelo valor da origem externa.
  • Greedy – Esse modo está intimamente relacionado ao Strict modo. Em vez de estar limitado a chaves que já existem na configuração original:

    • Os construtores de configuração adicionam todos os pares chave/valor da origem externa à seção de configuração resultante.
  • Expand – Opera no XML bruto antes de ser analisado em um objeto de seção de configuração. Ele pode ser considerado como uma expansão de tokens em uma cadeia de caracteres. Qualquer parte da cadeia de caracteres XML bruta que corresponda ao padrão ${token} é uma candidata à expansão do token. Se nenhum valor correspondente for encontrado na origem externa, o token não será alterado. Os construtores nesse 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 deweb.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 da propriedade como:

  • Os valores no arquivoweb.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á:

  • "Valor serviceID de web.config", se a variável ServiceID de ambiente não estiver definida.
  • O valor da ServiceID variável de ambiente, se definido.

A imagem a seguir mostra as <appSettings/> chaves/valores do conjunto de arquivosweb.config anterior no editor de ambiente:

A captura de tela mostra o editor de Variáveis Ambientais com as variáveis ServiceID e ServiceKey realçadas.

Observação: talvez seja necessário sair e reiniciar o Visual Studio para ver as alterações nas variáveis de ambiente.

Manipulação de prefixo

Os principais prefixos podem simplificar as chaves de configuração porque:

  • A configuração de .NET Framework é complexa e aninhada.
  • Fontes de chave/valor externas normalmente são básicas e simples por natureza. Por exemplo, as variáveis de ambiente não estão aninhadas.

Use qualquer uma das seguintes abordagens para injetar <appSettings/> e <connectionStrings/> na configuração por meio de variáveis de ambiente:

  • Com o EnvironmentConfigBuilder no modo padrão Strict e os nomes de chave apropriados no arquivo de configuração. O código e a marcação anteriores adotam essa abordagem. Usando essa abordagem , você não pode ter chaves nomeadas de forma idêntica em <appSettings/> e <connectionStrings/>.
  • Use dois EnvironmentConfigBuilders no Greedy modo com prefixos distintos e stripPrefix. Com essa abordagem, o aplicativo pode ler <appSettings/> e <connectionStrings/> sem a necessidade de atualizar o arquivo de configuração. A próxima seção, stripPrefix, mostra como fazer isso.
  • Use dois EnvironmentConfigBuilders no Greedy modo com prefixos distintos. Com essa abordagem, você não pode ter nomes de chave duplicados, pois os nomes de chave devem diferir 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 conjunto de arquivosweb.config anterior no editor de ambiente:

A captura de tela mostra o editor de Variáveis Ambientais com as variáveis AppSetting_default, AppSetting_ServiceID e ConnStr_default realçadas.

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 da propriedade como:

  • Os valores no arquivoweb.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 de env
ConnStr_default ConnStr_default val de env

stripPrefix

stripPrefix: booliano, 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 deve ser adicionado à ServiceID 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.

Os aplicativos normalmente removem o prefixo. O seguinteweb.config 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/> e <connectionStrings/>no .

A imagem a seguir mostra as <appSettings/> chaves/valores e <connectionStrings/> do conjunto de arquivosweb.config anterior no editor de ambiente:

A captura de tela mostra o editor de Variáveis Ambientais com as variáveis AppSetting_default, AppSetting_ServiceID e ConnStr_default realçadas.

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 da propriedade como:

  • Os valores no arquivoweb.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 de env
padrão ConnStr_default val de env

tokenPattern

tokenPattern: cadeia de caracteres, o padrão é @"\$\{(\w+)\}"

O Expand comportamento dos construtores pesquisa o XML bruto em busca de tokens semelhantes ${token}a . A pesquisa é feita com a expressão regular padrão @"\$\{(\w+)\}". O conjunto de caracteres que corresponde \w é mais estrito do que o XML e muitas fontes de configuração permitem. Use tokenPattern quando mais caracteres do que @"\$\{(\w+)\}" forem necessários no nome do token.

tokenPattern:String:

  • Permite que os desenvolvedores alterem o regex usado para correspondência de tokens.
  • 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 pesquisada na fonte de configuração.

Construtores de configuração no Microsoft.Configuration.ConfigurationBuilders

EnvironmentConfigBuilder

<add name="Environment"
    [mode|prefix|stripPrefix|tokenPattern] 
    type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder,
    Microsoft.Configuration.ConfigurationBuilders.Environment" />

O EnvironmentConfigBuilder:

  • É 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 em tempo de execução são injetadas apenas no ambiente de processo do EntryPoint. Os aplicativos executados como um serviço ou um processo não EntryPoint não captam essas variáveis, a menos que sejam injetadas por meio de um mecanismo no contêiner. Para contêineres baseados emASP.NET do IIS/, a versão atual do ServiceMonitor.exe lida com isso somente no DefaultAppPool. Outras variantes de contêiner baseadas no Windows podem precisar desenvolver seu próprio mecanismo de injeção para processos que não são do EntryPoint.

UserSecretsConfigBuilder

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 ~/ ou ~\. Por exemplo, o caminho pode ser gravado como userSecretsFile="~/secrets.file. Consulte a classe ConfigurationBuilders Utils para obter mais informações.

Esse construtor de configuração fornece um recurso semelhante a ASP.NET Core Secret Manager.

O UserSecretsConfigBuilder pode ser usado em projetos .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 projeto, o arquivo secreto é formatado em XML. A formatação XML é um detalhe de implementação e o formato não deve ser confiado. 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 - Esse é o método preferencial para identificar um arquivo de segredos XML. Ele funciona de forma semelhante ao .NET Core, que usa uma UserSecretsId propriedade de projeto para armazenar esse identificador. A cadeia de caracteres deve ser exclusiva, não precisa ser um GUID. Com esse atributo, a UserSecretsConfigBuilder aparência em um local conhecido (%APPDATA%\Microsoft\UserSecrets\<UserSecrets Id>\secrets.xml) para 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 o userSecretsId atributo são necessários. Se ambos forem especificados, userSecretsFile terá precedência.
  • optional: valor booliano e padrão true – 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>

AzureKeyVaultConfigBuilder

<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 Key Vault do Azure.

vaultName é necessário (o nome do cofre ou um URI para o cofre). Os outros atributos permitem o controle sobre a qual cofre se conectar, mas só são necessários se o aplicativo não estiver em execução em um ambiente que funcione com Microsoft.Azure.Services.AppAuthentication. A biblioteca de Autenticação dos Serviços do Azure é usada para obter 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 se uri não for fornecido. Especifica o nome do cofre em sua assinatura do Azure da qual ler pares chave/valor.
  • uri– Conecta-se a outros provedores de Key Vault com o valor especificadouri. Se não for especificado, o Azure (vaultName) será o provedor do cofre.
  • version– O Azure Key Vault fornece um recurso de controle de versão para segredos. Se version for especificado, o construtor só recuperará 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 como false. Definindo-o para false ler segredos um de cada vez. Ler segredos um de cada vez pode ser útil se o cofre permitir acesso "Obter", mas não "Listar". Nota: Ao usar Greedy o modo , preloadSecretNames deve ser true (o padrão.)

KeyPerFileConfigBuilder

<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ásico que usa 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 executar em um ambiente de contêiner orquestrado. Sistemas como Docker Swarm e Kubernetes fornecem secrets para seus contêineres orquestrados do Windows 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ções atravessa vários níveis do diretório, criando nomes de chave com esse delimitador. Se esse valor for null, o construtor de configurações examinará apenas o nível superior do diretório.
  • optional – O valor padrão é false. Especifica se o construtor de configurações deve causar erros se o diretório de origem não existir.

SimpleJsonConfigBuilder

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 de chave/valor específicas de .NET Framework configuração. Esse construtor de configuração não fornece configurações hierárquicas. O arquivo de suporte 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 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 - Booliano, o valor padrão é true. Impede a geração de exceções se o arquivo JSON não puder ser encontrado.

  • jsonMode - [Flat|Sectional]. Flat é o padrão. Quando jsonMode é Flat, o arquivo JSON é uma única fonte de chave/valor simples. AzureKeyVaultConfigBuilder E EnvironmentConfigBuilder também são fontes simples de chave/valor simples. Quando o SimpleJsonConfigBuilder está configurado no Sectional modo:

    • O arquivo JSON é conceitualmente dividido apenas no nível superior em vários dicionários.
    • Cada um dos dicionários só é aplicado à 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",
            }
        }
    }

Ordem dos construtores de configuração

Consulte ConfigurationBuilders Order of Execution no repositório GitHub aspnet/MicrosoftConfigurationBuilders .

Implementando um construtor de configuração de chave/valor personalizado

Se os construtores de configuração não atenderem às suas necessidades, você poderá escrever uma personalizada. A KeyValueConfigBuilder classe base manipula os modos de substituição e a maioria das preocupações de prefixo. Um projeto de implementação só precisa:

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.

Recursos adicionais