选项还提供验证配置数据的机制。 有关详细信息,请参阅
选项验证
部分。
本文介绍 ASP.NET Core 中的选项模式。 若要了解如何在控制台应用中使用选项模式,请参阅
.NET 中的选项模式
。
绑定分层配置
读取相关配置值的首选方法是使用
选项模式
。 例如,若要读取以下配置值,请执行以下操作:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
创建以下 PositionOptions
类:
public class PositionOptions
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
必须是非抽象的。
绑定在配置中具有相应项的类型的公共读写属性。
将其读写属性绑定到配置中的匹配条目。
请勿绑定字段。 在上面的代码中,Position
未绑定。 由于使用了 Position
字段,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position"
进行硬编码。
下面的代码:
调用 ConfigurationBinder.Bind 将 PositionOptions
类绑定到 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
ConfigurationBinder.Get<T>
绑定并返回指定的类型。 使用 ConfigurationBinder.Get<T>
可能比使用 ConfigurationBinder.Bind
更方便。 下面的代码演示如何将 ConfigurationBinder.Get<T>
与 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
Bind 还允许抽象类的缩进。 请看以下使用抽象类 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;
以下代码显示 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}"
对 Bind
的调用比对 Get<>
的调用严格:
Bind
允许抽象的缩进。
Get<>
必须创建实例本身。
使用选项模式时的另一种方法是绑定 Position
部分,并将其添加到依赖关系注入服务容器中。 在以下代码中,PositionOptions
已通过 Configure 被添加到了服务容器并已绑定到了配置:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
通过使用前面的代码,以下代码将读取位置选项:
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}");
在上面的代码中,不会读取在应用启动后对 JSON 配置文件所做的更改。 若要读取在应用启动后的更改,请使用 IOptionsSnapshot。
IOptions<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}");
以下代码注册 MyOptions
绑定的配置实例:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
在上面的代码中,读取在应用启动后对 JSON 配置文件所做的更改。
IOptionsMonitor
以下代码注册 MyOptions
绑定的配置实例。
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
下面的示例使用 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
命名选项:
当多个配置节绑定到同一属性时有用。
区分大小写。
请考虑以下 appsettings.json
文件:
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
下面的类用于每个节,而不是创建两个类来绑定 TopItem:Month
和 TopItem:Year
:
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;
下面的代码将配置命名选项:
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();
下面的代码将显示命名选项:
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" );
所有选项都是命名实例。 IConfigureOptions<TOptions> 实例将被视为面向 Options.DefaultName
实例,即 string.Empty
。 IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>。 IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。 null
命名选项用于面向所有命名实例,而不是某一特定命名实例。 ConfigureAll 和 PostConfigureAll 使用此约定。
OptionsBuilder API
OptionsBuilder<TOptions> 用于配置 TOptions
实例。 OptionsBuilder
简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName)
调用的单个参数,而不会出现在所有后续调用中。 选项验证和接受服务依赖关系的 ConfigureOptions
重载仅可通过 OptionsBuilder
获得。
OptionsBuilder
在选项验证部分中使用。
有关添加自定义存储库的信息,请参阅使用 AddOptions 配置自定义存储库。
在配置选项时,可以通过以下两种方式通过依赖关系注入访问服务:
将配置委托传递给 OptionsBuilder<TOptions> 上的 Configure。 OptionsBuilder<TOptions>
提供 Configure 的重载,该重载允许使用最多五个服务来配置选项:
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));
创建实现 IConfigureOptions<TOptions> 或 IConfigureNamedOptions<TOptions> 的类型,并将该类型注册为服务。
建议将配置委托传递给 Configure,因为创建服务较复杂。 在调用 Configure 时,创建类型等效于框架执行的操作。 调用 Configure 会注册一个临时通用 IConfigureNamedOptions<TOptions>,它具有可接受指定的通用服务类型的构造函数。
通过选项验证,可以验证选项值。
请考虑以下 appsettings.json
文件:
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
使用下面的类绑定到 "MyConfig"
配置节,并应用若干 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; }
下面的代码:
调用 AddOptions 以获取绑定到 MyConfigOptions
类的 OptionsBuilder<TOptions>。
调用 ValidateDataAnnotations 以使用 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();
ValidateDataAnnotations
扩展方法在 Microsoft.Extensions.Options.DataAnnotations NuGet 包中定义。 对于使用 Microsoft.NET.Sdk.Web
SDK 的 Web 应用,通过共享框架隐式引用此包。
下面的代码显示配置值或验证错误:
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;
var configValue = _config.Value;
catch (OptionsValidationException ex)
foreach (var failure in ex.Failures)
_logger.LogError(failure);
public ContentResult Index()
string msg;
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);
下面的代码使用委托应用更复杂的验证规则:
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();
IValidateOptions<TOptions>
和 IValidatableObject
下面的类实现了 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
允许将验证代码移出 Program.cs
并将其移入类中。
使用前面的代码,使用以下代码在 Program.cs
中启用验证:
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();
选项验证也支持 IValidatableObject。 若要对类中的某个类执行类级验证,请执行以下操作:
在类中实现 IValidatableObject
接口及其 Validate 方法。
在 Program.cs
中调用 ValidateDataAnnotations。
ValidateOnStart
选项验证将在第一次创建 IOptions<TOptions>、IOptionsSnapshot<TOptions> 或 IOptionsMonitor<TOptions> 实现时运行。 若要立即运行选项验证,请在应用启动时调用 Program.cs
中的 ValidateOnStart:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
选项后期配置
使用 IPostConfigureOptions<TOptions> 设置后期配置。 进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:
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";
PostConfigure 可用于对命名选项进行后期配置:
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();
使用 PostConfigureAll 对所有配置实例进行后期配置:
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";
访问 Program.cs
中的选项
若要访问 Program.cs
中的 IOptions<TOptions> 或 IOptionsMonitor<TOptions>,请在 WebApplication.Services 上调用 GetRequiredService:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
查看或下载示例代码(如何下载)
作者:Kirk Larkin 和 Rick Anderson。
选项模式使用类来提供对相关设置组的强类型访问。 当配置设置由方案隔离到单独的类时,应用遵循两个重要软件工程原则:
依赖于配置设置的类仅依赖于其使用的配置设置。
分离关注点:
- 应用的不同部件的设置不彼此依赖或相互耦合。
选项还提供验证配置数据的机制。 有关详细信息,请参阅选项验证部分。
本文介绍 ASP.NET Core 中的选项模式。 若要了解如何在控制台应用中使用选项模式,请参阅 .NET 中的选项模式。
绑定分层配置
读取相关配置值的首选方法是使用选项模式。 例如,若要读取以下配置值,请执行以下操作:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
创建以下 PositionOptions
类:
public class PositionOptions
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
必须是包含公共无参数构造函数的非抽象类。
类型的所有公共读写属性都已绑定。
字段不是绑定的。 在上面的代码中,Position
未绑定。 由于使用了 Position
字段,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position"
进行硬编码。
下面的代码:
调用 ConfigurationBinder.Bind 将 PositionOptions
类绑定到 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
ConfigurationBinder.Get<T>
绑定并返回指定的类型。 使用 ConfigurationBinder.Get<T>
可能比使用 ConfigurationBinder.Bind
更方便。 下面的代码演示如何将 ConfigurationBinder.Get<T>
与 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
使用选项模式时的另一种方法是绑定 Position
部分,并将其添加到依赖关系注入服务容器中。 在以下代码中,PositionOptions
已通过 Configure 被添加到了服务容器并已绑定到了配置:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
通过使用前面的代码,以下代码将读取位置选项:
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}");
在上面的代码中,不会读取在应用启动后对 JSON 配置文件所做的更改。 若要读取在应用启动后的更改,请使用 IOptionsSnapshot。
IOptions<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}");
以下代码注册 MyOptions
绑定的配置实例:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
在上面的代码中,读取在应用启动后对 JSON 配置文件所做的更改。
IOptionsMonitor
以下代码注册 MyOptions
绑定的配置实例。
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
下面的示例使用 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
命名选项:
当多个配置节绑定到同一属性时有用。
区分大小写。
请考虑以下 appsettings.json
文件:
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
下面的类用于每个节,而不是创建两个类来绑定 TopItem:Month
和 TopItem:Year
:
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;
下面的代码将配置命名选项:
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();
下面的代码将显示命名选项:
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" );
所有选项都是命名实例。 IConfigureOptions<TOptions> 实例将被视为面向 Options.DefaultName
实例,即 string.Empty
。 IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>。 IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。 null
命名选项用于面向所有命名实例,而不是某一特定命名实例。 ConfigureAll 和 PostConfigureAll 使用此约定。
OptionsBuilder API
OptionsBuilder<TOptions> 用于配置 TOptions
实例。 OptionsBuilder
简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName)
调用的单个参数,而不会出现在所有后续调用中。 选项验证和接受服务依赖关系的 ConfigureOptions
重载仅可通过 OptionsBuilder
获得。
OptionsBuilder
在选项验证部分中使用。
有关添加自定义存储库的信息,请参阅使用 AddOptions 配置自定义存储库。
在配置选项时,可以通过以下两种方式通过依赖关系注入访问服务:
将配置委托传递给 OptionsBuilder<TOptions> 上的 Configure。 OptionsBuilder<TOptions>
提供 Configure 的重载,该重载允许使用最多五个服务来配置选项:
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));
创建实现 IConfigureOptions<TOptions> 或 IConfigureNamedOptions<TOptions> 的类型,并将该类型注册为服务。
建议将配置委托传递给 Configure,因为创建服务较复杂。 在调用 Configure 时,创建类型等效于框架执行的操作。 调用 Configure 会注册一个临时通用 IConfigureNamedOptions<TOptions>,它具有可接受指定的通用服务类型的构造函数。
通过选项验证,可以验证选项值。
请考虑以下 appsettings.json
文件:
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
使用下面的类绑定到 "MyConfig"
配置节,并应用若干 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; }
下面的代码:
调用 AddOptions 以获取绑定到 MyConfigOptions
类的 OptionsBuilder<TOptions>。
调用 ValidateDataAnnotations 以使用 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();
ValidateDataAnnotations
扩展方法在 Microsoft.Extensions.Options.DataAnnotations NuGet 包中定义。 对于使用 Microsoft.NET.Sdk.Web
SDK 的 Web 应用,通过共享框架隐式引用此包。
下面的代码显示配置值或验证错误:
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;
var configValue = _config.Value;
catch (OptionsValidationException ex)
foreach (var failure in ex.Failures)
_logger.LogError(failure);
public ContentResult Index()
string msg;
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);
下面的代码使用委托应用更复杂的验证规则:
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();
IValidateOptions<TOptions>
和 IValidatableObject
下面的类实现了 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
允许将验证代码移出 Program.cs
并将其移入类中。
使用前面的代码,使用以下代码在 Program.cs
中启用验证:
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();
选项验证也支持 IValidatableObject。 若要对类中的某个类执行类级验证,请执行以下操作:
在类中实现 IValidatableObject
接口及其 Validate 方法。
在 Program.cs
中调用 ValidateDataAnnotations。
ValidateOnStart
选项验证将在第一次创建 IOptions<TOptions>、IOptionsSnapshot<TOptions> 或 IOptionsMonitor<TOptions> 实现时运行。 若要立即运行选项验证,请在应用启动时调用 Program.cs
中的 ValidateOnStart:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
选项后期配置
使用 IPostConfigureOptions<TOptions> 设置后期配置。 进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:
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";
PostConfigure 可用于对命名选项进行后期配置:
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();
使用 PostConfigureAll 对所有配置实例进行后期配置:
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";
访问 Program.cs
中的选项
若要访问 Program.cs
中的 IOptions<TOptions> 或 IOptionsMonitor<TOptions>,请在 WebApplication.Services 上调用 GetRequiredService:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
查看或下载示例代码(如何下载)
作者:Kirk Larkin 和 Rick Anderson。
选项模式使用类来提供对相关设置组的强类型访问。 当配置设置由方案隔离到单独的类时,应用遵循两个重要软件工程原则:
依赖于配置设置的类仅依赖于其使用的配置设置。
分离关注点:
- 应用的不同部件的设置不彼此依赖或相互耦合。
选项还提供验证配置数据的机制。 有关详细信息,请参阅选项验证部分。
本主题介绍 ASP.NET Core 中的选项模式。 若要了解如何在控制台应用中使用选项模式,请参阅 .NET 中的选项模式。
查看或下载示例代码(如何下载)
绑定分层配置
读取相关配置值的首选方法是使用选项模式。 例如,若要读取以下配置值,请执行以下操作:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
创建以下 PositionOptions
类:
public class PositionOptions
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
必须是包含公共无参数构造函数的非抽象类。
类型的所有公共读写属性都已绑定。
字段不是绑定的。 在上面的代码中,Position
未绑定。 由于使用了 Position
属性,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position"
进行硬编码。
下面的代码:
调用 ConfigurationBinder.Bind 将 PositionOptions
类绑定到 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
ConfigurationBinder.Get<T>
绑定并返回指定的类型。 使用 ConfigurationBinder.Get<T>
可能比使用 ConfigurationBinder.Bind
更方便。 下面的代码演示如何将 ConfigurationBinder.Get<T>
与 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
使用选项模式时的另一种方法是绑定 Position
部分,并将其添加到依赖关系注入服务容器中。 在以下代码中,PositionOptions
已通过 Configure 被添加到了服务容器并已绑定到了配置:
public void ConfigureServices(IServiceCollection services)
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
通过使用前面的代码,以下代码将读取位置选项:
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}");
在上面的代码中,不会读取在应用启动后对 JSON 配置文件所做的更改。 若要读取在应用启动后的更改,请使用 IOptionsSnapshot。
IOptions<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}");
以下代码注册 MyOptions
绑定的配置实例:
public void ConfigureServices(IServiceCollection services)
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
在上面的代码中,读取在应用启动后对 JSON 配置文件所做的更改。
IOptionsMonitor
以下代码注册 MyOptions
绑定的配置实例。
public void ConfigureServices(IServiceCollection services)
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
下面的示例使用 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}");
在上面的代码中,默认读取在应用启动后对 JSON 配置文件所做的更改。
命名选项:
当多个配置节绑定到同一属性时有用。
区分大小写。
请考虑以下 appsettings.json
文件:
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
下面的类用于每个节,而不是创建两个类来绑定 TopItem:Month
和 TopItem:Year
:
public class TopItemSettings
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; }
public string Model { get; set; }
下面的代码将配置命名选项:
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();
下面的代码将显示命名选项:
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" );
所有选项都是命名实例。 IConfigureOptions<TOptions> 实例将被视为面向 Options.DefaultName
实例,即 string.Empty
。 IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>。 IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。 null
命名选项用于面向所有命名实例,而不是某一特定命名实例。 ConfigureAll 和 PostConfigureAll 使用此约定。
OptionsBuilder API
OptionsBuilder<TOptions> 用于配置 TOptions
实例。 OptionsBuilder
简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName)
调用的单个参数,而不会出现在所有后续调用中。 选项验证和接受服务依赖关系的 ConfigureOptions
重载仅可通过 OptionsBuilder
获得。
OptionsBuilder
在选项验证部分中使用。
有关添加自定义存储库的信息,请参阅使用 AddOptions 配置自定义存储库。
在配置选项时,可以通过以下两种方式通过依赖关系注入访问服务:
将配置委托传递给 OptionsBuilder<TOptions> 上的 Configure。 OptionsBuilder<TOptions>
提供 Configure 的重载,该重载允许使用最多五个服务来配置选项:
services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
创建实现 IConfigureOptions<TOptions> 或 IConfigureNamedOptions<TOptions> 的类型,并将该类型注册为服务。
建议将配置委托传递给 Configure,因为创建服务较复杂。 在调用 Configure 时,创建类型等效于框架执行的操作。 调用 Configure 会注册一个临时通用 IConfigureNamedOptions<TOptions>,它具有可接受指定的通用服务类型的构造函数。
通过选项验证,可以验证选项值。
请考虑以下 appsettings.json
文件:
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
下面的类绑定到 "MyConfig"
配置节,并应用若干 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; }
下面的代码:
调用 AddOptions 以获取绑定到 MyConfigOptions
类的 OptionsBuilder<TOptions>。
调用 ValidateDataAnnotations 以使用 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();
ValidateDataAnnotations
扩展方法在 Microsoft.Extensions.Options.DataAnnotations NuGet 包中定义。 对于使用 Microsoft.NET.Sdk.Web
SDK 的 Web 应用,通过共享框架隐式引用此包。
下面的代码显示配置值或验证错误:
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;
var configValue = _config.Value;
catch (OptionsValidationException ex)
foreach (var failure in ex.Failures)
_logger.LogError(failure);
public ContentResult Index()
string msg;
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);
下面的代码使用委托应用更复杂的验证规则:
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();
用于复杂验证的 IValidateOptions
下面的类实现了 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
允许将验证代码移出 StartUp
并将其移入类中。
使用前面的代码,使用以下代码在 Startup.ConfigureServices
中启用验证:
public void ConfigureServices(IServiceCollection services)
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
services.AddControllersWithViews();
选项后期配置
使用 IPostConfigureOptions<TOptions> 设置后期配置。 进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:
services.PostConfigure<MyOptions>(myOptions =>
myOptions.Option1 = "post_configured_option1_value";
PostConfigure 可用于对命名选项进行后期配置:
services.PostConfigure<MyOptions>("named_options_1", myOptions =>
myOptions.Option1 = "post_configured_option1_value";
使用 PostConfigureAll 对所有配置实例进行后期配置:
services.PostConfigureAll<MyOptions>(myOptions =>
myOptions.Option1 = "post_configured_option1_value";
在启动期间访问选项
IOptions<TOptions> 和 IOptionsMonitor<TOptions> 可用于 Startup.Configure
中,因为在 Configure
方法执行之前已生成服务。
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
var option1 = optionsAccessor.CurrentValue.Option1;
不使用 Startup.ConfigureServices
中的 IOptions<TOptions> 或 IOptionsMonitor<TOptions>。 由于服务注册的顺序,可能存在不一致的选项状态。
ConfigurationExtensions NuGet 包
Microsoft.Extensions.Options.ConfigurationExtensions 包已在 ASP.NET Core 应用中隐式引用。