Options pattern: IOptions, Snapshot e Monitor
ResumoO Options Pattern liga seções de configuração a classes fortemente tipadas, injetadas via
IOptions<T>,IOptionsSnapshot<T>eIOptionsMonitor<T>— cada uma com um comportamento de recarga diferente.
1. Objetivos de Aprendizagem#
- Fazer binding de uma seção de configuração para uma classe.
- Escolher entre
IOptions,IOptionsSnapshoteIOptionsMonitor. - Validar opções na inicialização.
2. Pré-requisitos#
- Configuração e ambientes (Módulo 16).
3. Conceito#
Em vez de espalhar Configuration["JwtSettings:Issuer"] (strings frágeis), você faz o bind de JwtSettings para uma classe. O porquê: tipagem forte, validação e testabilidade. As três interfaces diferem no ciclo de vida:
IOptions<T>— singleton, valor lido uma vez; não reflete mudanças em runtime.IOptionsSnapshot<T>— scoped, recalculado por requisição; reflete mudanças de arquivo.IOptionsMonitor<T>— singleton com notificação de mudança; útil em serviços singleton/background.
4. Mão na Massa#
4.1. Setup#
Sem pacotes extras (Microsoft.Extensions.Options).
4.2. Implementação Passo a Passo#
- Classe de opções:
public class JwtSettings
{
public const string Section = "JwtSettings";
public string Issuer { get; set; } = default!;
public string Audience { get; set; } = default!;
public int ExpiresInMinutes { get; set; }
}
- Binding com validação:
builder.Services.AddOptions<JwtSettings>()
.Bind(builder.Configuration.GetSection(JwtSettings.Section))
.ValidateDataAnnotations()
.Validate(s => s.ExpiresInMinutes is > 0 and <= 60,
"ExpiresInMinutes deve estar entre 1 e 60.")
.ValidateOnStart();
- Consumo:
public class TokenService
{
private readonly JwtSettings _settings;
public TokenService(IOptions<JwtSettings> options) => _settings = options.Value;
}
4.3. Executando#
ValidateOnStart() faz a aplicação falhar no boot se a configuração for inválida — muito melhor do que descobrir em runtime.
5. Exemplo Completo#
IOptionsSnapshot para refletir alterações de appsettings.json sem reiniciar:
public class RelatorioService
{
private readonly RelatorioOptions _opts;
public RelatorioService(IOptionsSnapshot<RelatorioOptions> snap) => _opts = snap.Value;
}
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
| Usar classes de opções tipadas | Ler Configuration["a:b:c"] espalhado no código |
Validar com ValidateOnStart | Descobrir config inválida só em produção |
| Escolher a interface pelo ciclo de vida correto | Injetar IOptionsSnapshot em um singleton |
Atençãonão injete
IOptionsSnapshot<T>(scoped) em um serviço singleton — gera captive dependency. Em singletons/background services, useIOptionsMonitor<T>.
7. Segurança e Produção#
- Segredos (chaves, senhas) não pertencem ao
appsettings.json; combine o Options Pattern com user-secrets (dev) e variáveis de ambiente/secret store (prod). ValidateOnStartevita subir com configuração de segurança incompleta.
8. Exercícios#
- Fácil: faça o bind de
JwtSettingse injete viaIOptions. - Médio: adicione validação
Data Annotations([Required],[Range]) às opções. - Desafio: use
IOptionsMonitornum background service e reaja a mudanças de config.
9. Resumo#
O Options Pattern liga configuração a classes tipadas e validadas. IOptions/Snapshot/Monitor diferem no ciclo de vida e recarga — escolha conforme o consumidor. Segredos ficam fora do appsettings.
10. Próximos Passos#
Módulo 42: documentação da API com Swagger/OpenAPI.
11. Referências#
- Microsoft Learn — Options pattern no ASP.NET Core
- Microsoft Learn — Options no .NET
- Microsoft Learn — Validação de options