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 aplicações obterem valores de configuração de fontes externas.

Construtores de configuração:

  • Estão disponíveis no .NET Framework 4.7.1 e versões posteriores.
  • Fornecer um mecanismo flexível para ler valores de configuração.
  • Responda a algumas das necessidades básicas das aplicações à medida que avançam para um ambiente focado em contentores e cloud.
  • Pode ser usado para melhorar a proteção dos dados de configuração ao recorrer a fontes anteriormente indisponíveis (por exemplo, Azure Key Vault e variáveis de ambiente) no sistema de configuração .NET.

Construtores de configuração chave/valor

Um cenário comum que pode ser tratado por construtores de configuração é fornecer um mecanismo básico de substituição chave/valor para secções de configuração que seguem um padrão chave/valor. O conceito do .NET Framework dos ConfigurationBuilders não se limita a secções ou padrões de configuração específicos. No entanto, muitos dos construtores de configuração no Microsoft.Configuration.ConfigurationBuilders (github, NuGet) trabalham dentro do padrão chave/valor.

Definições de construtores de configuração chave/valor

As seguintes definições aplicam-se a todos os construtores de configuração chave/valor em Microsoft.Configuration.ConfigurationBuilders.

Mode

Os construtores de configuração utilizam uma fonte externa de informação chave/valor para preencher elementos chave/valor selecionados do sistema de configuração. Especificamente, as secções <appSettings/> e <connectionStrings/> recebem tratamento especial pelos construtores de configurações. Os construtores trabalham em três modos:

  • Strict - O modo padrão. Neste modo, o construtor de configuração opera apenas em secções de configuração bem conhecidas centradas em chave/valor. Strict O modo enumera cada tecla na secção. Se uma chave correspondente for encontrada na fonte externa:

    • Os construtores de configuração substituem o valor na secção de configuração resultante pelo valor da fonte externa.
  • Greedy - Este modo está intimamente relacionado com o Strict modo. Em vez de se restringir a chaves que já existem na configuração original:

    • Os construtores de configuração adicionam todos os pares chave/valor da fonte externa na secção de configuração resultante.
  • Expand - Opera no XML bruto antes de ser analisado num objeto de secção de configuração. Pode ser entendida como uma expansão de fichas numa cadeia. Qualquer parte da cadeia XML bruta que corresponda ao padrão ${token} é candidata à expansão do token. Se não for encontrado valor correspondente na fonte externa, então o token não é alterado. Os construtores neste modo não se limitam às secções <appSettings/> e <connectionStrings/>.

A seguinte marcação no web.config permite 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 seguinte código lê o <appSettings/> e o <connectionStrings/> mostrados no ficheiro 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 das propriedades para:

  • Os valores no ficheiroweb.config se as chaves não estiverem definidas nas variáveis de ambiente.
  • Os valores da variável ambiente, se definidos.

Por exemplo, ServiceID irá conter:

  • "Valor de 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 seguinte mostra as <appSettings/> chaves/valores do ficheiro web.config anterior definido no editor de ambiente:

A captura de ecrã mostra o editor de Variáveis Ambientais com as variáveis ServiceID e ServiceKey destacadas.

Nota: Pode ser necessário sair e reiniciar o Visual Studio para ver alterações nas variáveis do ambiente.

Tratamento de prefixos

Os prefixos de teclas podem simplificar a configuração de teclas porque:

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

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

  • Com o EnvironmentConfigBuilder no modo predefinido Strict e os nomes de chaves apropriados no ficheiro de configuração. O código e a marcação anteriores adotam esta abordagem. Usando esta abordagem, não possam ter chaves com nomes idênticos tanto em <appSettings/> como em <connectionStrings/>.
  • Use dois EnvironmentConfigBuilders no modo Greedy com prefixos distintos e stripPrefix. Com esta abordagem, a aplicação pode ler <appSettings/> e <connectionStrings/> sem necessidade de atualizar o ficheiro de configuração. A secção seguinte, stripPrefix, mostra como fazer isto.
  • Use dois EnvironmentConfigBuilders em modo Greedy com prefixos distintos. Com esta abordagem, não se podem ter nomes-chave duplicados, pois os nomes-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 plana pode ser usada para preencher a configuração de duas secções diferentes.

A imagem seguinte mostra as chaves/valores <appSettings/> e <connectionStrings/> do ficheiro web.config anterior estabelecido no editor de ambientes:

A captura de ecrã mostra o editor de Variáveis Ambientais com as variáveis AppSetting_default, AppSetting_ServiceID e ConnStr_default destacadas.

O seguinte código lê as chaves/valores <appSettings/> e <connectionStrings/> contidos no ficheiro 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 das propriedades para:

  • Os valores no ficheiro web.config caso as chaves não estejam definidas nas variáveis de ambiente.
  • Os valores da variável ambiente, se definidos.

Por exemplo, usando o ficheiro web.config anterior, as chaves/valores na imagem do editor de ambiente anterior e o código anterior, os seguintes valores são definidos:

Chave Valor
AppSetting_ServiceID AppSetting_ServiceID a partir de variáveis ambientales
AppSetting_default AppSetting_valor padrão do ambiente de execução
ConnStr_default Valor padrão ConnStr de ambiente

stripPrefix

stripPrefix: booleano, por padrão é false.

A marcação XML anterior separa as definições da aplicação das strings de ligação, mas exige que todas as teclas do ficheiroweb.config usem o prefixo especificado. Por exemplo, o prefixo AppSetting deve ser adicionado à chave ServiceID ("AppSetting_ServiceID"). Com stripPrefix, o prefixo não é usado no ficheiroweb.config . O prefixo é exigido no código-fonte do construtor de configuração (por exemplo, no ambiente). Prevemos que a maioria dos programadores utilizará stripPrefix.

As aplicações normalmente removem o prefixo. O seguinte web.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 ficheiro web.config anterior, a chave default está tanto no <appSettings/> como no <connectionStrings/>.

A imagem seguinte mostra as chaves/valores <appSettings/> e <connectionStrings/> do conjunto de ficheiros web.config anterior no editor de ambientes.

A captura de ecrã mostra o editor de Variáveis Ambientais com as variáveis AppSetting_default, AppSetting_ServiceID e ConnStr_default destacadas.

O seguinte código lê as chaves/valores <appSettings/> e <connectionStrings/> contidos no ficheiro 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 das propriedades para:

  • Os valores no ficheiroweb.config se as chaves não estiverem definidas nas variáveis de ambiente.
  • Os valores da variável ambiente, se definidos.

Por exemplo, usando o ficheiro web.config anterior, as chaves/valores na imagem do editor de ambiente anterior e o código anterior, os seguintes valores são definidos:

Chave Valor
ID do serviço AppSetting_ServiceID a partir de variáveis ambientales
predefinição AppSetting_valor padrão do ambiente
predefinição Valor padrão de ConnStr do ambiente

tokenPattern

tokenPattern: String, predefinido para @"\$\{(\w+)\}"

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

tokenPattern: Texto:

  • Permite aos programadores alterar o regex usado para a correspondência de tokens.
  • Não é feita qualquer validação para garantir que é um regex bem formado e não perigoso.
  • Deve conter um grupo de captura. Todo o regex tem de corresponder ao token inteiro. A primeira captura deve ser o nome do token para consultar 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 opções de configuração adicionais.
  • O name valor do atributo é arbitrário.

Nota: Num ambiente de contentores Windows, as variáveis definidas em tempo de execução são apenas injetadas no ambiente de processos EntryPoint. As aplicações que correm como um serviço ou um processo não-EntryPoint não captam estas variáveis a menos que sejam injetadas através de um mecanismo no contentor. Para containers baseadosem ASP.NET/, a versão atual do ServiceMonitor.exe trata disto apenas no DefaultAppPool. Outras variantes de contentores baseadas no Windows podem precisar de desenvolver o seu próprio mecanismo de injeção para processos que não sejam EntryPoint.

UserSecretsConfigBuilder

Advertência

Nunca armazene palavras-passe, cadeias de ligação sensíveis ou outros dados sensíveis no código-fonte. 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 poderia ser escrito como userSecretsFile="~/secrets.file. Consulte a classe Utils do ConfigurationBuilders para mais informações.

Este construtor de configuração oferece uma funcionalidade semelhante ao ASP.NET Core Secret Manager.

O UserSecretsConfigBuilder pode ser usado em projetos do .NET Framework, mas é necessário especificar um ficheiro de segredos. Em alternativa, pode definir a UserSecretsId propriedade no ficheiro do projeto e criar o ficheiro de segredos brutos no local correto para leitura. Para manter dependências externas fora do seu projeto, o ficheiro secreto é formatado em XML. A formatação XML é um detalhe de implementação, e o formato não deve ser considerado confiável. Se precisar de partilhar um ficheiro secrets.json com projetos .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 preferido para identificar um ficheiro de segredos XML. Funciona de forma semelhante ao .NET Core, que utiliza uma UserSecretsId propriedade de projeto para armazenar este identificador. A string tem de ser única, não precisa de ser um GUID. Com este atributo, o UserSecretsConfigBuilder irá procurar numa localização local bem conhecida (%APPDATA%\Microsoft\UserSecrets\<UserSecrets Id>\secrets.xml) um arquivo de segredos pertencente a este identificador.
  • userSecretsFile - Um atributo opcional que especifica o ficheiro que contém os segredos. O ~ carácter pode ser usado no início para referenciar a raiz da aplicação. Ou este atributo ou o userSecretsId atributo é obrigatório. Se ambos forem especificados, userSecretsFile tem prioridade.
  • optional: booleano, valor true padrão - Impede uma exceção se o ficheiro secrets não for encontrado.
  • O name valor do atributo é arbitrário.

O ficheiro 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>

ConstrutorDeConfiguraçõesAzureKeyVault

<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 é obrigatório (seja o nome do cofre ou um URI para o cofre). Os outros atributos permitem controlar a que vault ligar, mas só são necessários se a aplicação não estiver a correr num ambiente que funcione com Microsoft.Azure.Services.AppAuthentication. A biblioteca de Autenticação de Serviços Azure é usada para recolher automaticamente informações de ligação do ambiente de execução, se possível. Pode sobrescrever a recolha automática da informação de ligação fornecendo uma cadeia de ligação.

  • vaultName - Obrigatório se uri não for fornecido. Especifica o nome de um cofre na sua subscrição do Azure de onde deve ler pares chave/valor.
  • uri - Liga-se a outros fornecedores de Key Vault com o valor especificado uri . Se não especificado, Azure (vaultName) é o fornecedor do vault.
  • version - Azure Key Vault fornece uma funcionalidade de versionamento para segredos. Caso version seja especificado, o construtor só recupera segredos que coincidam com esta versão.
  • preloadSecretNames - Por padrão, este gerador consulta todos os nomes de chave no repositório de chaves quando é inicializado. Para evitar a leitura de todos os valores-chave, defina este atributo para false. Ao configurar isto para false, lê-se os segredos um a um. Ler segredos um a um pode ser útil se o vault permitir o acesso "Get" mas não o acesso "List". 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 utiliza os ficheiros de um diretório como fonte de valores. O nome de um ficheiro é a chave, e o conteúdo é o valor. Este construtor de configuração pode ser útil quando está a correr num ambiente de contentores orquestrados. Sistemas como o Docker Swarm e o Kubernetes fornecem secrets aos seus contentores do Windows de forma key-per-file.

Detalhes do atributo:

  • directoryPath -Necessário. Especifica um caminho para procurar por valores. Os segredos do Docker para Windows são armazenados por defeito no diretório C:\ProgramData\Docker\ secrets.
  • ignorePrefix - Ficheiros que começam com este prefixo são excluídos. Por defeito, "ignorar".
  • keyDelimiter - O valor padrão é null. Se especificado, o construtor de configuração percorre vários níveis do diretório, construindo nomes-chave com este delimitador. Se este valor for null, o construtor de configuração apenas vê o nível superior do diretório.
  • optional - O valor padrão é false. Especifica se o construtor de configuração deve causar erros caso o diretório de origem não exista.

SimpleJsonConfigBuilder

Advertência

Nunca armazene palavras-passe, cadeias de ligação sensíveis ou outros dados sensíveis no código-fonte. 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 .NET Core utilizam frequentemente ficheiros JSON para configuração. O construtor SimpleJsonConfigBuilder permite que ficheiros JSON .NET Core sejam usados no .NET Framework. Este construtor de configuração fornece um mapeamento básico de uma fonte plana de chave/valor para áreas específicas de chave/valor da configuração do .NET Framework. Este construtor de configurações não prevê configurações hierárquicas. O ficheiro de suporte JSON é semelhante a um dicionário, não a um objeto hierárquico complexo. Pode ser utilizado um ficheiro hierárquico multinível. Este fornecedor flattenobtém a profundidade acrescentando o nome da propriedade em cada nível usando : como delimitador.

Detalhes do atributo:

  • jsonFile -Necessário. Especifica o ficheiro JSON a ler. O ~ carácter pode ser usado no início para referenciar a raiz da aplicação.

  • optional - Booleano, valor padrão é true. Impede o lançamento de exceções se o ficheiro JSON não for encontrado.

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

    • O ficheiro JSON é conceptualmente dividido apenas ao nível superior em múltiplos dicionários.
    • Cada um dos dicionários é aplicado apenas à secção de configuração que corresponde ao nome da propriedade de nível superior associado a cada um deles. Por exemplo:
    {
        "appSettings" : {
            "setting1" : "value1",
            "setting2" : "value2",
            "complex" : {
                "setting1" : "complex:value1",
                "setting2" : "complex:value2",
            }
        }
    }

Ordem dos construtores de configuração

Consulte a Ordem de Execução do ConfigurationBuilders no repositório GitHub do aspnet/MicrosoftConfigurationBuilders .

Implementação de um construtor personalizado de configuração de chaves/valores

Se os construtores de configuração não corresponderem às tuas necessidades, podes escrever um personalizado. A KeyValueConfigBuilder classe base trata dos modos de substituição e da maioria das preocupações com prefixos. Um projeto de implementação precisa apenas:

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 construtores de configuração chave/valor.

Recursos adicionais