IRONSOFTWAREHOME

O Padrão de Opções em C#

The Options Pattern in C#

Tim Corey

10m 15s

A configuração em aplicações .NET geralmente reside em appsettings.json, variáveis de ambiente ou segredos do usuário. Extrair esses dados de configuração de um arquivo e inseri-los nas suas classes de uma maneira limpa e testável é o que o padrão de opções resolve. Em vez de ler manualmente as chaves JSON ou passar strings brutas, você vincula uma seção de configuração a uma classe C# fortemente tipada e permite que a injeção de dependência a entregue onde for necessário.

Em seu vídeo "The Options Pattern in C#", Tim Corey introduz as três variações do padrão de opções (IOptions, IOptionsSnapshot, e IOptionsMonitor), demonstra cada uma em um aplicativo de servidor Blazor, e mostra como adicionar validação para que sua aplicação falhe rapidamente quando falta configuração ou está malformada. Se você está construindo qualquer projeto .NET que leia de arquivos de configuração e use injeção de dependência, este padrão é fundamental.

A Configuração: Um Modelo POCO e appsettings.json

[0:34 - 1:46] Tim começa com um aplicativo Blazor (renderizado no lado do servidor, sem interatividade no lado do cliente) que já tem duas partes em funcionamento. A primeira é uma seção em appsettings.json com três pares de chave-valor sob uma seção CloudInfo:

// appsettings.json
{
  "CloudInfo": {
    "Storage": "https://storage.example.com",
    "Website": "https://www.example.com",
    "API": "https://api.example.com"
  }
}
C#

A segunda peça é uma classe simples em C# (um POCO) cujas propriedades espelham as chaves JSON:

public class CloudInfoOptions
{
    public string Storage { get; set; }
    public string Website { get; set; }
    public string API { get; set; }
}
C#

Tim observa que a fonte de configuração não precisa ser appsettings.json especificamente. Pode ser appsettings.Development.json, secrets.json, ou qualquer combinação. O padrão de opções lê de qualquer provedor de configuração registrado no aplicativo, e os nomes das propriedades no POCO correspondem às chaves JSON por convenção.

Registrando Opções em Program.cs

[2:25 - 3:15] Conectar a configuração à injeção de dependência exige duas chamadas de método em Program.cs:

// Register CloudInfoOptions bound to the "CloudInfo" section
builder.Services.AddOptions<CloudInfoOptions>()
    .BindConfiguration("CloudInfo");
C#

AddOptions<t>() registra o tipo com DI. BindConfiguration("CloudInfo") informa ao framework qual seção da configuração mapear. A string "CloudInfo" corresponde à chave JSON em appsettings.json. Se o nome da seção e o nome da classe não corresponderem, o argumento de string é o que a estrutura usa para encontrar os dados corretos.

IOptions: A Abordagem Singleton

[3:15 - 5:18] Com o registro no lugar, Tim injeta a configuração em uma página Blazor usando IOptions<CloudInfoOptions>:

@inject IOptions<CloudInfoOptions> CloudConfig

@code {
    protected override void OnInitialized()
    {
        var options = CloudConfig.Value;
        // options.Storage, options.Website, options.API are available
    }
}
C#

O detalhe crítico é que IOptions<t> está registrado como um singleton. Os valores de configuração são lidos uma vez quando o aplicativo inicia e armazenados em cache pela vida útil do processo. Se você mudar appsettings.json enquanto o aplicativo está em execução, IOptions não refletirá essas mudanças.

Para a maioria dos aplicativos, essa é a escolha certa. A configuração raramente muda em tempo de execução, e o tempo de vida como singleton significa zero sobrecarga por solicitação.

IOptionsSnapshot: Recarregamento Controlado

[5:18 - 6:55] Tim troca IOptions por IOptionsSnapshot para demonstrar a variante com escopo:

@inject IOptionsSnapshot<CloudInfoOptions> CloudConfig
C#

IOptionsSnapshot<t> lê a configuração novamente para cada solicitação (tempo de vida com escopo). Se você modificar appsettings.json enquanto o aplicativo está em execução, a próxima solicitação web captará os novos valores. A solicitação anterior mantém seu próprio snapshot, então não há inconsistência no meio da solicitação.

Isso é útil para aplicativos onde as mudanças de configuração precisam entrar em vigor sem reiniciar, como ativar/desativar flags de função, atualizar endpoints de API ou rodar strings de conexão de armazenamento. A troca é um pequeno custo por solicitação para reler a configuração, o qual é insignificante para a maioria das cargas de trabalho.

IOptionsMonitor: Notificações de Mudança ao Vivo

[6:55 - 8:34] A terceira variante, IOptionsMonitor<t>, vai além do recarregamento de instantâneos. Ele monitora ativamente as mudanças de configuração e pode disparar callbacks quando os valores são atualizados:

@inject IOptionsMonitor<CloudInfoOptions> CloudConfig

@code {
    protected override void OnInitialized()
    {
        // Current values
        var current = CloudConfig.CurrentValue;

        // Register a callback for live changes
        CloudConfig.OnChange(updatedOptions =>
        {
            // React to configuration changes in real time
        });
    }
}
C#

Ao contrário de IOptionsSnapshot, que atualiza apenas entre solicitações, IOptionsMonitor pode detectar mudanças durante uma operação de longa duração. Tim aponta que isso é mais relevante para serviços de fundo, hubs SignalR ou qualquer componente com um tempo de vida mais longo que uma única solicitação HTTP.

Adicionando Validação

[8:34 - 10:05] The final piece Tim covers is validation. O padrão de opções suporta regras de validação inline que são executadas quando a configuração é acessada pela primeira vez:

builder.Services.AddOptions<CloudInfoOptions>()
    .BindConfiguration("CloudInfo")
    .Validate(opts =>
        !string.IsNullOrEmpty(opts.Storage) &&
        !string.IsNullOrEmpty(opts.Website) &&
        !string.IsNullOrEmpty(opts.API));
C#

Tim demonstra o caso de falha removendo o valor Storage de appsettings.json e lançando o aplicativo. O resultado é uma exceção não tratada imediata: "CloudInfoOptions falhou na validação." O aplicativo se recusa a iniciar com a configuração incompleta, o que é exatamente o comportamento que você deseja. Descobrir um valor ausente na inicialização é muito melhor do que atingir uma referência nula em produção às 2 da manhã.

Para cenários de validação mais complexos (verificações entre propriedades, regras condicionais), você pode encadear múltiplas chamadas .Validate() ou implementar IValidateOptions<t> como uma classe de validação dedicada.

Concluindo: Três Interfaces, Um Padrão

[10:05 - 10:10] O padrão de opções fornece uma separação clara entre armazenamento e consumo de configuração. IOptions cobre a maioria dos casos de uso onde a configuração é estática. IOptionsSnapshot lida com aplicativos que precisam captar mudanças entre solicitações. IOptionsMonitor serve componentes de longa execução que necessitam de conhecimento em tempo real das atualizações de configuração. E a validação garante que seu aplicativo falhe ruidosamente quando valores obrigatórios estão ausentes.

Conclusão

[10:10 - 10:15] Para resumir: registre sua configuração com AddOptions<t>().BindConfiguration("SectionName") em Program.cs, injete uma das três interfaces (IOptions, IOptionsSnapshot, ou IOptionsMonitor) dependendo dos seus requisitos de recarregamento, e adicione .Validate() para capturar valores faltantes no início ao invés de em tempo de execução.

O padrão funciona em qualquer tipo de projeto .NET: Blazor, ASP.NET Core, aplicativos de console, serviços de trabalho. O registro é o mesmo em todos os lugares.

Dica de exemplo: Se você não tem certeza de qual interface usar, comece com IOptions<t>. É o mais simples, não tem sobrecarga por solicitação e cobre a vasta maioria dos casos onde a configuração é definida na inicialização e não muda. Só mude para IOptionsSnapshot ou IOptionsMonitor quando você tiver uma necessidade concreta de recarregamento em tempo de execução.

Assista o vídeo completo vídeo em seu Canal no YouTube e obtenha mais insights sobre padrões de configuração em C#.

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

Obtenha sua chave de avaliação gratuita de 30 dias instantaneamente.

Your trial license will be sent to your email address

Sem limitações. 100% desbloqueado. Sem cartão de crédito.

bullet_checkedNão é necessário cartão de crédito nem criação de conta.Sem limitações. 100% desbloqueado. Sem cartão de crédito.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Agende sua consulta sem compromisso.
Preencha o formulário abaixo ou envie um e-mail para sales@ironsoftware.com
Os seus dados serão sempre mantidos em sigilo.
Aprovado por milhões de engenheiros em todo o mundo.
Logotipos dos clientes da Iron Software
Obtenha sua chave de avaliação gratuita de 30 dias instantaneamente.
Não é necessário cartão de crédito nem criação de conta.