Eventos
Campeonato Mundial de Visualização de Dados do Power BI
14 de fev., 16 - 31 de mar., 16
Com 4 chances de participar, você pode ganhar um pacote de conferência e chegar à Grande Final AO VIVO em Las Vegas
Saiba maisNão há mais suporte para esse navegador.
Atualize o Microsoft Edge para aproveitar os recursos, o suporte técnico e as atualizações de segurança mais recentes.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Por Rick Anderson.
O padrão de opções usa classes para fornecer acesso fortemente tipado a grupos de configurações relacionadas. Quando as definições de configuração são isoladas por cenário em classes separadas, o aplicativo segue dois princípios importantes de engenharia de software:
As opções também fornecem um mecanismo para validar os dados da configuração. Para obter mais configurações, consulte a seção Validação de opções.
Esse artigo fornece informações sobre o padrão de opções no ASP.NET Core. Para obter informações sobre como usar o padrão de opções em aplicativos de console, consulte Padrão de opções no .NET.
A maneira preferencial de ler os valores de configuração relacionados é usando o padrão de opções. Por exemplo, para ler os seguintes valores de configuração:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Crie a seguinte classe PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Uma classe de opções:
Position
não está vinculado. O campo Position
é usado para que a cadeia de caracteres "Position"
não precise ser codificada no aplicativo ao associar a classe a um provedor de configuração.O seguinte código:
PositionOptions
à seção Position
.Position
.public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
ConfigurationBinder.Get<T>
associa e retorna o tipo especificado. ConfigurationBinder.Get<T>
pode ser mais conveniente do que usar ConfigurationBinder.Bind
. O código a seguir mostra como usar ConfigurationBinder.Get<T>
com a classe PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions? positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
A associação também permite a concretização de uma classe abstrata. Considere o código a seguir que usa a classe abstrata SomethingWithAName
:
namespace ConfigSample.Options;
public abstract class SomethingWithAName
{
public abstract string? Name { get; set; }
}
public class NameTitleOptions(int age) : SomethingWithAName
{
public const string NameTitle = "NameTitle";
public override string? Name { get; set; }
public string Title { get; set; } = string.Empty;
public int Age { get; set; } = age;
}
O código a seguir exibe os valores de configuração NameTitleOptions
:
public class Test33Model : PageModel
{
private readonly IConfiguration Configuration;
public Test33Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var nameTitleOptions = new NameTitleOptions(22);
Configuration.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);
return Content($"Title: {nameTitleOptions.Title} \n" +
$"Name: {nameTitleOptions.Name} \n" +
$"Age: {nameTitleOptions.Age}"
);
}
}
As chamadas para Bind
são menos restritas do que as chamadas para Get<>
:
Bind
permite a concretização de um resumo.Get<>
tem que criar uma instância própria.Uma abordagem alternativa ao usar o padrão de opções é associar a seção Position
e adicioná-la ao contêiner do serviço de injeção de dependência. No código a seguir, PositionOptions
é adicionada ao contêiner de serviço com Configure e associada à configuração:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Usando o código anterior, o código a seguir lê as opções de posição:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
No código anterior, as alterações no arquivo de configuração JSON após a inicialização do aplicativo não são lidas. Para ler as alterações após a inicialização do aplicativo, use IOptionsSnapshot.
TOptions
.Os cenários de Pós-configuração permitem definir ou alterar as opções depois de todas as configurações do IConfigureOptions<TOptions> serem feitas.
O IOptionsFactory<TOptions> é responsável por criar novas instâncias de opções. Ele tem um único método Create. A implementação padrão usa todos os IConfigureOptions<TOptions> e IPostConfigureOptions<TOptions> registrados e executa todas as configurações primeiro, seguidas da pós-configuração. Ela faz distinção entre IConfigureNamedOptions<TOptions> e IConfigureOptions<TOptions> e chama apenas a interface apropriada.
O IOptionsMonitorCache<TOptions> é usado pelo IOptionsMonitor<TOptions> para armazenar em cache as instâncias do TOptions
. O IOptionsMonitorCache<TOptions> invalida as instâncias de opções no monitor, de modo que o valor seja recalculado (TryRemove). Os valores podem ser manualmente inseridos com TryAdd. O método Clear é usado quando todas as instâncias nomeadas devem ser recriadas sob demanda.
Usando IOptionsSnapshot<TOptions>:
A diferença entre IOptionsMonitor
e IOptionsSnapshot
é que:
IOptionsMonitor
é um serviço de banco de dados individual que recupera valores de opção atuais a qualquer momento, o que é especialmente útil em dependências de banco de dados individual.IOptionsSnapshot
é um serviço com escopo e fornece um instantâneo das opções no momento em que o objeto IOptionsSnapshot<T>
é construído. Os instantâneos de opções são projetados para uso com dependências transitórias e com escopo.O código a seguir usa IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
O código a seguir registra uma instância de configuração que MyOptions
associa a:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
No código anterior, as alterações no arquivo de configuração JSON após o aplicativo iniciar a leitura.
O código a seguir registra uma instância de configuração a que MyOptions
se associa.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
O exemplo a seguir usa IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
Opções nomeadas:
Considere o seguinte arquivo appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Em vez de criar duas classes para associar TopItem:Month
e TopItem:Year
, a seguinte classe é usada para cada seção:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
O código a seguir configura as opções nomeadas:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
O código a seguir mostra as opções nomeadas:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Todas as opções são instâncias nomeadas. As instâncias IConfigureOptions<TOptions> existentes são tratadas como sendo direcionadas à instância Options.DefaultName
, que é string.Empty
. IConfigureNamedOptions<TOptions> também implementa IConfigureOptions<TOptions>. A implementação padrão de IOptionsFactory<TOptions> tem lógica para usar cada um de forma adequada. A opção nomeada null
é usada para direcionar todas as instâncias nomeadas, em vez de uma instância nomeada específica. ConfigureAll e PostConfigureAll usam essa convenção.
OptionsBuilder<TOptions> é usada para configurar instâncias TOptions
. OptionsBuilder
simplifica a criação de opções nomeadas, pois é apenas um único parâmetro para a chamada AddOptions<TOptions>(string optionsName)
inicial, em vez de aparecer em todas as chamadas subsequentes. A validação de opções e as sobrecargas ConfigureOptions
que aceitam dependências de serviço só estão disponíveis por meio de OptionsBuilder
.
OptionsBuilder
é usado na seção Validação de opções.
Consulte Usar AddOptions para configurar o repositório personalizado para obter informações sobre como adicionar um repositório personalizado.
Os serviços podem ser acessados de injeção de dependência ao configurar as opções de duas maneiras:
Aprova um representante de configuração para Configure em OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
oferece sobrecargas de Configure que permitem usar até cinco serviços para configurar opções:
builder.Services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Criar um tipo que implementa IConfigureOptions<TOptions> ou IConfigureNamedOptions<TOptions> e registra o tipo como um serviço.
É recomendável transmitir um delegado de configuração para Configure, já que a criação de um serviço é algo mais complexo. A criação de um tipo é equivalente ao que a estrutura faz ao chamar Configure. Chamar Configure registra um genérico transitório IConfigureNamedOptions<TOptions>, que tem um construtor que aceita os tipos de serviço genérico especificados.
A validação de opções permite que valores de opção sejam validados.
Considere o seguinte arquivo appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
A classe a seguir é usada para se associar à seção de configuração "MyConfig"
e aplica algumas regras de DataAnnotations
:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
O seguinte código:
MyConfigOptions
.DataAnnotations
.using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
O método de extensão ValidateDataAnnotations
é definido no pacote Microsoft.Extensions.Options.DataAnnotations do NuGet. Para aplicativos Web que usam o SDK Microsoft.NET.Sdk.Web
, esse pacote é referenciado implicitamente da estrutura compartilhada.
O código a seguir exibe os valores de configuração ou os erros de validação:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
O código a seguir aplica uma regra de validação mais complexa usando um representante:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
var app = builder.Build();
A classe a seguir implementa IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string? vor = null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1!);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
permite retirar o código de validação do Program.cs
e colocar em uma classe.
Usando o código anterior, a validação está habilitada em Program.cs
com o seguinte código:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
A validação de opções também dá suporte a IValidatableObject. Para executar a validação de nível de classe de uma classe dentro da própria classe:
IValidatableObject
e seu método Validate dentro da classe .Program.cs
.A validação de opções é executada na primeira vez que uma TOption
instância é criada. Isso significa, por exemplo, quando o primeiro acesso ocorre em um pipeline de IOptionsSnapshot<TOptions>.Value
solicitação ou quando IOptionsMonitor<TOptions>.Get(string)
é chamado nas configurações presentes. Depois que as configurações são recarregadas, a validação é executada novamente. O runtime do ASP.NET Core usa OptionsCache<TOptions> para armazenar em cache a instância de opções depois que ela é criada.
Para executar rapidamente a validação de opções, quando o aplicativo for iniciado, chame ValidateOnStart<TOptions>(OptionsBuilder<TOptions>) em Program.cs
:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Defina a pós-configuração com IPostConfigureOptions<TOptions>. A pós-configuração é executada depois que toda o configuração de IConfigureOptions<TOptions> é feita:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
O PostConfigure está disponível para pós-configurar opções nomeadas:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Use PostConfigureAll para pós-configurar todas as instâncias de configuração:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Para acessar IOptions<TOptions> ou IOptionsMonitor<TOptions> em Program.cs
, chame GetRequiredService em WebApplication.Services:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Por Kirk Larkin e Rick Anderson.
O padrão de opções usa classes para fornecer acesso fortemente tipado a grupos de configurações relacionadas. Quando as definições de configuração são isoladas por cenário em classes separadas, o aplicativo segue dois princípios importantes de engenharia de software:
As opções também fornecem um mecanismo para validar os dados da configuração. Para obter mais configurações, consulte a seção Validação de opções.
Esse artigo fornece informações sobre o padrão de opções no ASP.NET Core. Para obter informações sobre como usar o padrão de opções em aplicativos de console, consulte Padrão de opções no .NET.
A maneira preferencial de ler os valores de configuração relacionados é usando o padrão de opções. Por exemplo, para ler os seguintes valores de configuração:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Crie a seguinte classe PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Uma classe de opções:
Position
não está vinculado. O campo Position
é usado para que a cadeia de caracteres "Position"
não precise ser codificada no aplicativo ao associar a classe a um provedor de configuração.O seguinte código:
PositionOptions
à seção Position
.Position
.public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
ConfigurationBinder.Get<T>
associa e retorna o tipo especificado. ConfigurationBinder.Get<T>
pode ser mais conveniente do que usar ConfigurationBinder.Bind
. O código a seguir mostra como usar ConfigurationBinder.Get<T>
com a classe PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions? positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
Uma abordagem alternativa ao usar o padrão de opções é associar a seção Position
e adicioná-la ao contêiner do serviço de injeção de dependência. No código a seguir, PositionOptions
é adicionada ao contêiner de serviço com Configure e associada à configuração:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Usando o código anterior, o código a seguir lê as opções de posição:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
No código anterior, as alterações no arquivo de configuração JSON após a inicialização do aplicativo não são lidas. Para ler as alterações após a inicialização do aplicativo, use IOptionsSnapshot.
TOptions
.Os cenários de Pós-configuração permitem definir ou alterar as opções depois de todas as configurações do IConfigureOptions<TOptions> serem feitas.
O IOptionsFactory<TOptions> é responsável por criar novas instâncias de opções. Ele tem um único método Create. A implementação padrão usa todos os IConfigureOptions<TOptions> e IPostConfigureOptions<TOptions> registrados e executa todas as configurações primeiro, seguidas da pós-configuração. Ela faz distinção entre IConfigureNamedOptions<TOptions> e IConfigureOptions<TOptions> e chama apenas a interface apropriada.
O IOptionsMonitorCache<TOptions> é usado pelo IOptionsMonitor<TOptions> para armazenar em cache as instâncias do TOptions
. O IOptionsMonitorCache<TOptions> invalida as instâncias de opções no monitor, de modo que o valor seja recalculado (TryRemove). Os valores podem ser manualmente inseridos com TryAdd. O método Clear é usado quando todas as instâncias nomeadas devem ser recriadas sob demanda.
Usando IOptionsSnapshot<TOptions>:
A diferença entre IOptionsMonitor
e IOptionsSnapshot
é que:
IOptionsMonitor
é um serviço de banco de dados individual que recupera valores de opção atuais a qualquer momento, o que é especialmente útil em dependências de banco de dados individual.IOptionsSnapshot
é um serviço com escopo e fornece um instantâneo das opções no momento em que o objeto IOptionsSnapshot<T>
é construído. Os instantâneos de opções são projetados para uso com dependências transitórias e com escopo.O código a seguir usa IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
O código a seguir registra uma instância de configuração que MyOptions
associa a:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
No código anterior, as alterações no arquivo de configuração JSON após o aplicativo iniciar a leitura.
O código a seguir registra uma instância de configuração a que MyOptions
se associa.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
O exemplo a seguir usa IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
Opções nomeadas:
Considere o seguinte arquivo appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Em vez de criar duas classes para associar TopItem:Month
e TopItem:Year
, a seguinte classe é usada para cada seção:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
O código a seguir configura as opções nomeadas:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
O código a seguir mostra as opções nomeadas:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Todas as opções são instâncias nomeadas. As instâncias IConfigureOptions<TOptions> existentes são tratadas como sendo direcionadas à instância Options.DefaultName
, que é string.Empty
. IConfigureNamedOptions<TOptions> também implementa IConfigureOptions<TOptions>. A implementação padrão de IOptionsFactory<TOptions> tem lógica para usar cada um de forma adequada. A opção nomeada null
é usada para direcionar todas as instâncias nomeadas, em vez de uma instância nomeada específica. ConfigureAll e PostConfigureAll usam essa convenção.
OptionsBuilder<TOptions> é usada para configurar instâncias TOptions
. OptionsBuilder
simplifica a criação de opções nomeadas, pois é apenas um único parâmetro para a chamada AddOptions<TOptions>(string optionsName)
inicial, em vez de aparecer em todas as chamadas subsequentes. A validação de opções e as sobrecargas ConfigureOptions
que aceitam dependências de serviço só estão disponíveis por meio de OptionsBuilder
.
OptionsBuilder
é usado na seção Validação de opções.
Consulte Usar AddOptions para configurar o repositório personalizado para obter informações sobre como adicionar um repositório personalizado.
Os serviços podem ser acessados de injeção de dependência ao configurar as opções de duas maneiras:
Aprova um representante de configuração para Configure em OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
oferece sobrecargas de Configure que permitem usar até cinco serviços para configurar opções:
builder.Services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Criar um tipo que implementa IConfigureOptions<TOptions> ou IConfigureNamedOptions<TOptions> e registra o tipo como um serviço.
É recomendável transmitir um delegado de configuração para Configure, já que a criação de um serviço é algo mais complexo. A criação de um tipo é equivalente ao que a estrutura faz ao chamar Configure. Chamar Configure registra um genérico transitório IConfigureNamedOptions<TOptions>, que tem um construtor que aceita os tipos de serviço genérico especificados.
A validação de opções permite que valores de opção sejam validados.
Considere o seguinte arquivo appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
A classe a seguir é usada para se associar à seção de configuração "MyConfig"
e aplica algumas regras de DataAnnotations
:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
O seguinte código:
MyConfigOptions
.DataAnnotations
.using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
O método de extensão ValidateDataAnnotations
é definido no pacote Microsoft.Extensions.Options.DataAnnotations do NuGet. Para aplicativos Web que usam o SDK Microsoft.NET.Sdk.Web
, esse pacote é referenciado implicitamente da estrutura compartilhada.
O código a seguir exibe os valores de configuração ou os erros de validação:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
O código a seguir aplica uma regra de validação mais complexa usando um representante:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
var app = builder.Build();
A classe a seguir implementa IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string? vor = null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1!);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
permite retirar o código de validação do Program.cs
e colocar em uma classe.
Usando o código anterior, a validação está habilitada em Program.cs
com o seguinte código:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
A validação de opções também dá suporte a IValidatableObject. Para executar a validação de nível de classe de uma classe dentro da própria classe:
IValidatableObject
e seu método Validate dentro da classe .Program.cs
.A validação de opções é executada na primeira vez que uma implementação IOptions<TOptions>, IOptionsSnapshot<TOptions>ou IOptionsMonitor<TOptions> é criada. Para executar rapidamente a validação de opções, quando o aplicativo for iniciado, chame ValidateOnStart em Program.cs
:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Defina a pós-configuração com IPostConfigureOptions<TOptions>. A pós-configuração é executada depois que toda o configuração de IConfigureOptions<TOptions> é feita:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
O PostConfigure está disponível para pós-configurar opções nomeadas:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Use PostConfigureAll para pós-configurar todas as instâncias de configuração:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Para acessar IOptions<TOptions> ou IOptionsMonitor<TOptions> em Program.cs
, chame GetRequiredService em WebApplication.Services:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Por Kirk Larkin e Rick Anderson.
O padrão de opções usa classes para fornecer acesso fortemente tipado a grupos de configurações relacionadas. Quando as definições de configuração são isoladas por cenário em classes separadas, o aplicativo segue dois princípios importantes de engenharia de software:
As opções também fornecem um mecanismo para validar os dados da configuração. Para obter mais configurações, consulte a seção Validação de opções.
Esse tópico fornece informações sobre o padrão de opções no ASP.NET Core. Para obter informações sobre como usar o padrão de opções em aplicativos de console, consulte Padrão de opções no .NET.
Exibir ou baixar código de exemplo (como baixar)
A maneira preferencial de ler os valores de configuração relacionados é usando o padrão de opções. Por exemplo, para ler os seguintes valores de configuração:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Crie a seguinte classe PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
}
Uma classe de opções:
Position
não está vinculado. A propriedade Position
é usada para que a cadeia de caracteres "Position"
não precise ser codificada no aplicativo ao associar a classe a um provedor de configuração.O seguinte código:
PositionOptions
à seção Position
.Position
.public class Test22Model : PageModel
{
private readonly IConfiguration Configuration;
public Test22Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
ConfigurationBinder.Get<T>
associa e retorna o tipo especificado. ConfigurationBinder.Get<T>
pode ser mais conveniente do que usar ConfigurationBinder.Bind
. O código a seguir mostra como usar ConfigurationBinder.Get<T>
com a classe PositionOptions
:
public class Test21Model : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions positionOptions { get; private set; }
public Test21Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position)
.Get<PositionOptions>();
return Content($"Title: {positionOptions.Title} \n" +
$"Name: {positionOptions.Name}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
Uma abordagem alternativa ao usar o padrão de opções é associar a seção Position
e adicioná-la ao contêiner do serviço de injeção de dependência. No código a seguir, PositionOptions
é adicionada ao contêiner de serviço com Configure e associada à configuração:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
}
Usando o código anterior, o código a seguir lê as opções de posição:
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content($"Title: {_options.Title} \n" +
$"Name: {_options.Name}");
}
}
No código anterior, as alterações no arquivo de configuração JSON após a inicialização do aplicativo não são lidas. Para ler as alterações após a inicialização do aplicativo, use IOptionsSnapshot.
TOptions
.Os cenários de Pós-configuração permitem definir ou alterar as opções depois de todas as configurações do IConfigureOptions<TOptions> serem feitas.
O IOptionsFactory<TOptions> é responsável por criar novas instâncias de opções. Ele tem um único método Create. A implementação padrão usa todos os IConfigureOptions<TOptions> e IPostConfigureOptions<TOptions> registrados e executa todas as configurações primeiro, seguidas da pós-configuração. Ela faz distinção entre IConfigureNamedOptions<TOptions> e IConfigureOptions<TOptions> e chama apenas a interface apropriada.
O IOptionsMonitorCache<TOptions> é usado pelo IOptionsMonitor<TOptions> para armazenar em cache as instâncias do TOptions
. O IOptionsMonitorCache<TOptions> invalida as instâncias de opções no monitor, de modo que o valor seja recalculado (TryRemove). Os valores podem ser manualmente inseridos com TryAdd. O método Clear é usado quando todas as instâncias nomeadas devem ser recriadas sob demanda.
Usando IOptionsSnapshot<TOptions>, as opções são computadas uma vez por solicitação, quando acessadas e armazenadas em cache durante o tempo de vida da solicitação. As alterações na configuração são lidas depois que o aplicativo é iniciado ao usar provedores de configuração que permitem a leitura de valores de configuração atualizados.
A diferença entre IOptionsMonitor
e IOptionsSnapshot
é que:
IOptionsMonitor
é um serviço de banco de dados individual que recupera valores de opção atuais a qualquer momento, o que é especialmente útil em dependências de banco de dados individual.IOptionsSnapshot
é um serviço com escopo e fornece um instantâneo das opções no momento em que o objeto IOptionsSnapshot<T>
é construído. Os instantâneos de opções são projetados para uso com dependências transitórias e com escopo.O código a seguir usa IOptionsSnapshot<TOptions>.
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
public ContentResult OnGet()
{
return Content($"Option1: {_snapshotOptions.Option1} \n" +
$"Option2: {_snapshotOptions.Option2}");
}
}
O código a seguir registra uma instância de configuração que MyOptions
associa a:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
No código anterior, as alterações no arquivo de configuração JSON após o aplicativo iniciar a leitura.
O código a seguir registra uma instância de configuração a que MyOptions
se associa.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
O exemplo a seguir usa IOptionsMonitor<TOptions>:
public class TestMonitorModel : PageModel
{
private readonly IOptionsMonitor<MyOptions> _optionsDelegate;
public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
{
_optionsDelegate = optionsDelegate;
}
public ContentResult OnGet()
{
return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
$"Option2: {_optionsDelegate.CurrentValue.Option2}");
}
}
No código anterior, por padrão, as alterações no arquivo de configuração JSON após a inicialização do aplicativo são lidas.
Opções nomeadas:
Considere o seguinte arquivo appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Em vez de criar duas classes para associar TopItem:Month
e TopItem:Year
, a seguinte classe é usada para cada seção:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; }
public string Model { get; set; }
}
O código a seguir configura as opções nomeadas:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<TopItemSettings>(TopItemSettings.Month,
Configuration.GetSection("TopItem:Month"));
services.Configure<TopItemSettings>(TopItemSettings.Year,
Configuration.GetSection("TopItem:Year"));
services.AddRazorPages();
}
O código a seguir mostra as opções nomeadas:
public class TestNOModel : PageModel
{
private readonly TopItemSettings _monthTopItem;
private readonly TopItemSettings _yearTopItem;
public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
{
_monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
_yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
}
public ContentResult OnGet()
{
return Content($"Month:Name {_monthTopItem.Name} \n" +
$"Month:Model {_monthTopItem.Model} \n\n" +
$"Year:Name {_yearTopItem.Name} \n" +
$"Year:Model {_yearTopItem.Model} \n" );
}
}
Todas as opções são instâncias nomeadas. As instâncias IConfigureOptions<TOptions> existentes são tratadas como sendo direcionadas à instância Options.DefaultName
, que é string.Empty
. IConfigureNamedOptions<TOptions> também implementa IConfigureOptions<TOptions>. A implementação padrão de IOptionsFactory<TOptions> tem lógica para usar cada um de forma adequada. A opção nomeada null
é usada para direcionar todas as instâncias nomeadas, em vez de uma instância nomeada específica. ConfigureAll e PostConfigureAll usam essa convenção.
OptionsBuilder<TOptions> é usada para configurar instâncias TOptions
. OptionsBuilder
simplifica a criação de opções nomeadas, pois é apenas um único parâmetro para a chamada AddOptions<TOptions>(string optionsName)
inicial, em vez de aparecer em todas as chamadas subsequentes. A validação de opções e as sobrecargas ConfigureOptions
que aceitam dependências de serviço só estão disponíveis por meio de OptionsBuilder
.
OptionsBuilder
é usado na seção Validação de opções.
Consulte Usar AddOptions para configurar o repositório personalizado para obter informações sobre como adicionar um repositório personalizado.
Os serviços podem ser acessados de injeção de dependência ao configurar as opções de duas maneiras:
Aprova um representante de configuração para Configure em OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
oferece sobrecargas de Configure que permitem usar até cinco serviços para configurar opções:
services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Criar um tipo que implementa IConfigureOptions<TOptions> ou IConfigureNamedOptions<TOptions> e registra o tipo como um serviço.
É recomendável transmitir um delegado de configuração para Configure, já que a criação de um serviço é algo mais complexo. A criação de um tipo é equivalente ao que a estrutura faz ao chamar Configure. Chamar Configure registra um genérico transitório IConfigureNamedOptions<TOptions>, que tem um construtor que aceita os tipos de serviço genérico especificados.
A validação de opções permite que valores de opção sejam validados.
Considere o seguinte arquivo appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
A classe a seguir associa-se à seção de configuração "MyConfig"
e aplica algumas regras de DataAnnotations
:
public class MyConfigOptions
{
public const string MyConfig = "MyConfig";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string Key1 { get; set; }
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Key2 { get; set; }
public int Key3 { get; set; }
}
O seguinte código:
MyConfigOptions
.DataAnnotations
.public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<MyConfigOptions>()
.Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
services.AddControllersWithViews();
}
O método de extensão ValidateDataAnnotations
é definido no pacote Microsoft.Extensions.Options.DataAnnotations do NuGet. Para aplicativos Web que usam o SDK Microsoft.NET.Sdk.Web
, esse pacote é referenciado implicitamente da estrutura compartilhada.
O código a seguir exibe os valores de configuração ou os erros de validação:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptions<MyConfigOptions> _config;
public HomeController(IOptions<MyConfigOptions> config,
ILogger<HomeController> logger)
{
_config = config;
_logger = logger;
try
{
var configValue = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (var failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
public ContentResult Index()
{
string msg;
try
{
msg = $"Key1: {_config.Value.Key1} \n" +
$"Key2: {_config.Value.Key2} \n" +
$"Key3: {_config.Value.Key3}";
}
catch (OptionsValidationException optValEx)
{
return Content(optValEx.Message);
}
return Content(msg);
}
O código a seguir aplica uma regra de validação mais complexa usando um representante:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions<MyConfigOptions>()
.Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Key2 != 0)
{
return config.Key3 > config.Key2;
}
return true;
}, "Key3 must be > than Key2."); // Failure message.
services.AddControllersWithViews();
}
A classe a seguir implementa IValidateOptions<TOptions>:
public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public MyConfigOptions _config { get; private set; }
public MyConfigValidation(IConfiguration config)
{
_config = config.GetSection(MyConfigOptions.MyConfig)
.Get<MyConfigOptions>();
}
public ValidateOptionsResult Validate(string name, MyConfigOptions options)
{
string vor=null;
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
var match = rx.Match(options.Key1);
if (string.IsNullOrEmpty(match.Value))
{
vor = $"{options.Key1} doesn't match RegEx \n";
}
if ( options.Key2 < 0 || options.Key2 > 1000)
{
vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
}
if (_config.Key2 != default)
{
if(_config.Key3 <= _config.Key2)
{
vor += "Key3 must be > than Key2.";
}
}
if (vor != null)
{
return ValidateOptionsResult.Fail(vor);
}
return ValidateOptionsResult.Success;
}
}
IValidateOptions
permite retirar o código de validação do StartUp
e colocar em uma classe.
Usando o código anterior, a validação está habilitada em Startup.ConfigureServices
com o seguinte código:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
services.AddControllersWithViews();
}
Defina a pós-configuração com IPostConfigureOptions<TOptions>. A pós-configuração é executada depois que toda o configuração de IConfigureOptions<TOptions> é feita:
services.PostConfigure<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
O PostConfigure está disponível para pós-configurar opções nomeadas:
services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Use PostConfigureAll para pós-configurar todas as instâncias de configuração:
services.PostConfigureAll<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
IOptions<TOptions> e IOptionsMonitor<TOptions> podem ser usados em Startup.Configure
, pois os serviços são criados antes da execução do método Configure
.
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
{
var option1 = optionsAccessor.CurrentValue.Option1;
}
Não use IOptions<TOptions> ou IOptionsMonitor<TOptions> em Startup.ConfigureServices
. Pode haver um estado inconsistente de opções devido à ordenação dos registros de serviço.
O pacote Microsoft.Extensions.Options.ConfigurationExtensions é referenciado implicitamente em aplicativos ASP.NET Core.
Comentários do ASP.NET Core
O ASP.NET Core é um projeto código aberto. Selecione um link para fornecer comentários:
Eventos
Campeonato Mundial de Visualização de Dados do Power BI
14 de fev., 16 - 31 de mar., 16
Com 4 chances de participar, você pode ganhar um pacote de conferência e chegar à Grande Final AO VIVO em Las Vegas
Saiba maisTreinamento
Módulo
Configurar serviços com injeção de dependência no ASP.NET Core - Training
Entenda e implemente a injeção de dependência em um aplicativo ASP.NET Core. Use o contêiner de serviço interno do ASP.NET Core para gerenciar dependências. Registre serviços com o contêiner de serviço.
Documentação
Conheça o padrão de opções para representar grupos de configurações relacionadas em aplicativos .NET. Esse padrão de opções usa classes para fornecer acesso fortemente tipado a configurações.
Saiba como usar a API de configuração para configurar AppSettings em um aplicativo ASP.NET Core.