Às vezes é necessário obter as configurações de forma dinâmica para a aplicação, baseado no tipo de ambiente que vai executar, como produção ou desenvolvimento, ou até mesmo alterando seu comportamento durante a execução da aplicação.
Para começar será feita uma breve introdução e configuração que será utilizada durante todo o artigo.
IConfiguration
Representa os valores das fontes de dados no formato chave-valor que podem ser de vários formatos como yaml, json, xml, variáveis de ambiente, banco de dados, api, etc.
Configurando a aplicação
Instale a extensão Microsoft.Extensions.Configuration
Adicione as chaves abaixo no arquivo appsettings.json.
"Paginas": {
"Servicos": {
"Titulo": "Serviços",
"Ativo": true
}
}
Crie o arquivo ServicosConfig.cs e adicione o código abaixo nele.
public class ServicosConfig
{
public string? Titulo { get; set; }
public bool Ativo { get; set; }
}
Adicione no arquivo Program.cs, ou no antigo arquivo Startup.cs, a linha abaixo para obter a configuração por seção do arquivo appsettings.json.
builder.Services.Configure<ServicosConfig>(builder.Configuration.GetSection("Paginas:Servicos"));
IOptions
É registrado como Singleton e utilizado durante todo o ciclo de vida da aplicação, não podendo ler as atualizações depois de inicializado.
// Controller ...
[HttpGet]
[Route("/ioptions")]
public void OperacaoComIOptions([FromServices] IOptions<ServicosConfig> options)
{
ServicosConfig cfg = options.Value;
// …
}
Obtendo valores sem parar ou recompilar a aplicação
As interfaces IOptionsSnapshot<T>
e IOptionsMonitor<T>
observam alterações na fonte de dados da configuração para manter atualizados na aplicação, mesmo depois de inicializadas.
Como visto com IOptions é necessário parar ou recompilar a aplicação para as configurações serem atualizadas.
IOptionsSnapshot
Faz uma cópia atualizada das configurações para disponibilizar durante as solicitações. Isso significa que se a configuração for alterada, a próxima atualização estará disponível na solicitação seguinte e não em tempo real durante uma operação.
// Controller …
[HttpGet]
[Route("/snapshot")]
public void OperacaoComIOptionsSnapshot([FromServices] IOptionsSnapshot<ServicosConfig> options)
{
ServicosConfig cfg = options.Value;
// …
}
Faça o seguinte para ver como funciona:
- Coloque um breakpoint antes de acessar o valor da configuração;
- Altere e salve o valor no appsettings.json;
Repare que o valor não é atualizado durante a requisição, mas se fizer uma nova requisição o valor estará atualizado.
IOptionsMonitor
É registrado como Singleton, isso significa que se o valor for alterado mesmo que manualmente isso terá efeito para todo os outros locais que utilizam, mas a grande diferença é que IOptionsMonitor dispara um evento em tempo real quando existe atualização das configurações, e o desenvolvedor pode escolher entre usar a configuração antiga ou a nova durante a execução de uma operação.
É útil para usar valores atualizados a qualquer momento ou em operações de longa duração onde nem todos os valores são utilizados no começo da operação.
Um cenário que dá para utilizar IOptionsMonitor é em Flag-Feature quando uma funcionalidade é desativada no meio da operação e nisso pode disparar o CancellationTokenSource
para interromper a operação em execução.
[HttpGet]
[Route("/longaduracao")]
public async Task LongaDuracao([FromServices] IOptionsMonitor<ServicosConfig> options)
{
ServicosConfig cfg = options.CurrentValue;
var cts = new CancellationTokenSource();
// Registra para receber notificações de atualizações
options.OnChange((novaConfig, s) =>
{
// Atualiza a configuração APENAS do método LongaDuracao.
cfg = novaConfig;
// Verifica a situação da funcionalidade
if (cfg.Ativo == false)
{
// Notifica para cancelar a execução da operação.
cts.Cancel();
}
});
if (cfg.Ativo)
{
// Simula uma execução demorada.
await Task.Delay(delay: TimeSpan.FromHours(1), cts.Token);
}
// …
}