ASP.NET Core 中的选项模式Options pattern in ASP.NET Core

本文内容

选项模式使用类来表示相关设置的组。配置设置由方案隔离到单独的类时,应用遵循两个重要软件工程原则:

选项还提供验证配置数据的机制。有关详细信息,请参阅选项验证部分。

查看或下载示例代码如何下载

PackagePackage

Microsoft.Extensions.Options.ConfigurationExtensions 包已在 ASP.NET Core 应用中隐式引用。

选项接口Options interfaces

IOptionsMonitor<TOptions> 用于检索选项并管理 TOptions 实例的选项通知。IOptionsMonitor<TOptions> 支持以下方案:

IOptionsFactory<TOptions> 负责新建选项实例。它具有单个 Create 方法。默认实现采用所有已注册 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions> 并首先运行所有配置,然后才进行后期配置。它区分 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions> 且仅调用适当的接口。

IOptionsMonitorCache<TOptions>IOptionsMonitor<TOptions> 用于缓存 TOptions 实例。IOptionsMonitorCache<TOptions> 可使监视器中的选项实例无效,以便重新计算值 (TryRemove)。可以通过 TryAdd 手动引入值。在应按需重新创建所有命名实例时使用 Clear 方法。

IOptionsSnapshot<TOptions> 在每次请求时应重新计算选项的方案中有用。有关详细信息,请参阅通过 IOptionsSnapshot 重新加载配置数据部分。

IOptions<TOptions> 可用于支持选项。但是,IOptions<TOptions> 不支持前面的 IOptionsMonitor<TOptions> 方案。你可以在已使用 IOptions<TOptions> 接口的现有框架和库中继续使用 IOptions<TOptions>,并且不需要 IOptionsMonitor<TOptions> 提供的方案。

常规选项配置General options configuration

常规选项配置已作为示例 1 在示例应用中进行了演示。

选项类必须为包含公共无参数构造函数的非抽象类。以下类 MyOptions 具有两种属性:Option1Option2设置默认值为可选,但以下示例中的类构造函数设置了 Option1 的默认值。Option2 具有通过直接初始化属性设置的默认值 (Models/MyOptions.cs ):

  1. public class MyOptions
  2. {
  3. public MyOptions()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

MyOptions 类已通过 Configure 添加到服务容器并绑定到配置:

  1. // Example #1: General configuration
  2. // Register the Configuration instance which MyOptions binds against.
  3. services.Configure<MyOptions>(Configuration);

以下页面模型通过 IOptionsMonitor<TOptions> 使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs ):

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #1: Simple options
  2. var option1 = _options.Option1;
  3. var option2 = _options.Option2;
  4. SimpleOptions = $"option1 = {option1}, option2 = {option2}";

示例的 appsettings.json 文件指定 option1option2 的值:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Information",
  11. "Microsoft": "Warning",
  12. "Microsoft.Hosting.Lifetime": "Information"
  13. }
  14. },
  15. "AllowedHosts": "*"
  16. }

运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. option1 = value1_from_json, option2 = -1

备注

使用自定义 ConfigurationBuilder 从设置文件加载选项配置时,请确认基路径设置正确:

  1. var configBuilder = new ConfigurationBuilder()
  2. .SetBasePath(Directory.GetCurrentDirectory())
  3. .AddJsonFile("appsettings.json", optional: true);
  4. var config = configBuilder.Build();
  5. services.Configure<MyOptions>(config);

通过 CreateDefaultBuilder 从设置文件加载选项配置时,不需要显式设置基路径。

通过委托配置简单选项Configure simple options with a delegate

通过委托配置简单选项已作为示例 2 在示例应用中进行了演示。

使用委托设置选项值。此示例应用使用 MyOptionsWithDelegateConfig 类 (Models/MyOptionsWithDelegateConfig.cs ):

  1. public class MyOptionsWithDelegateConfig
  2. {
  3. public MyOptionsWithDelegateConfig()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

在以下代码中,已向服务容器添加第二个 IConfigureOptions<TOptions> 服务。它通过 MyOptionsWithDelegateConfig 使用委托来配置绑定:

  1. // Example #2: Options bound and configured by a delegate
  2. services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
  3. {
  4. myOptions.Option1 = "value1_configured_by_delegate";
  5. myOptions.Option2 = 500;
  6. });

Index.cshtml.cs :

  1. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #2: Options configured by delegate
  2. var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
  3. var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
  4. SimpleOptionsWithDelegateConfig =
  5. $"delegate_option1 = {delegate_config_option1}, " +
  6. $"delegate_option2 = {delegate_config_option2}";

可添加多个配置提供程序。配置提供程序可从 NuGet 包中获取,并按照注册的顺序应用。有关详细信息,请参阅 ASP.NET Core 中的配置

每次调用 Configure 都会将 IConfigureOptions<TOptions> 服务添加到服务容器。在前面的示例中,Option1Option2 的值同时在 appsettings.json 中指定,但 Option1Option2 的值被配置的委托替代。

当启用多个配置服务时,指定的最后一个配置源优于其他源 ,由其设置配置值。运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子选项配置Suboptions configuration

子选项配置已作为示例 3 在示例应用中进行了演示。

应用应创建适用于应用中特定方案组(类)的选项类。需要配置值的部分应用应仅有权访问其使用的配置值。

将选项绑定到配置时,选项类型中的每个属性都将绑定到窗体 property[:sub-property:] 的配置键。例如,MyOptions.Option1 属性将绑定到从 appsettings.json 中的 option1 属性读取的键 Option1

在以下代码中,已向服务容器添加第三个 IConfigureOptions<TOptions> 服务。它将 MySubOptions 绑定到 appsettings.json 文件的 subsection 部分:

  1. // Example #3: Suboptions
  2. // Bind options using a sub-section of the appsettings.json file.
  3. services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

GetSection 方法需要 Microsoft.Extensions.Configuration 命名空间。

示例的 appsettings.json 文件定义具有 suboption1suboption2 的键的 subsection 成员:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Information",
  11. "Microsoft": "Warning",
  12. "Microsoft.Hosting.Lifetime": "Information"
  13. }
  14. },
  15. "AllowedHosts": "*"
  16. }

MySubOptions 类将属性 SubOption1SubOption2 定义为保留选项值 (Models/MySubOptions.cs ):

  1. public class MySubOptions
  2. {
  3. public MySubOptions()
  4. {
  5. // Set default values.
  6. SubOption1 = "value1_from_ctor";
  7. SubOption2 = 5;
  8. }
  9. public string SubOption1 { get; set; }
  10. public int SubOption2 { get; set; }
  11. }

页面模型的 OnGet 方法返回包含选项值的字符串 (Pages/Index.cshtml.cs ):

  1. private readonly MySubOptions _subOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #3: Suboptions
  2. var subOption1 = _subOptions.SubOption1;
  3. var subOption2 = _subOptions.SubOption2;
  4. SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

运行应用时,OnGet 方法返回显示子选项类值的字符串:

  1. subOption1 = subvalue1_from_json, subOption2 = 200

选项注入Options injection

选项注入已作为示例 4 在示例应用中进行了演示。

IOptionsMonitor<TOptions> 注入:

  • 使用 @inject Razor 指令的 Razor 页面或 MVC 视图。
  • 页面或视图模型。

示例应用中的以下示例将 IOptionsMonitor<TOptions> 注入页面模型 (Pages/Index.cshtml.cs):

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #4: Bind options directly to the page
  2. MyOptions = _options;

示例应用演示如何使用 @inject 指令注入 IOptionsMonitor<MyOptions>

  1. @page
  2. @model IndexModel
  3. @using Microsoft.Extensions.Options
  4. @inject IOptionsMonitor<MyOptions> OptionsAccessor
  5. @{
  6. ViewData["Title"] = "Options Sample";
  7. }
  8. <h1>@ViewData["Title"]</h1>

当应用运行时,选项值显示在呈现的页面中:

选项值 Option1:value1_from_json 和 Option2:-1 从模型中加载并注入视图。

通过 IOptionsSnapshot 重新加载配置数据Reload configuration data with IOptionsSnapshot

通过 IOptionsSnapshot<TOptions> 重新加载配置数据已作为示例 5 在示例应用中进行了演示。

通过使用 IOptionsSnapshot<TOptions>,针对请求生存期访问和缓存选项时,每个请求都会计算一次选项。

IOptionsMonitorIOptionsSnapshot 之间的区别在于:

  • IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。
  • IOptionsSnapshot 是一种作用域服务,并在构造 IOptionsSnapshot<T> 对象时提供选项的快照。选项快照旨在用于暂时性和有作用域的依赖项。

以下示例演示如何在更改 appsettings.json (Pages/Index.cshtml.cs ) 后创建新的 IOptionsSnapshot<TOptions>在更改文件和重新加载配置之前,针对服务器的多个请求返回 appsettings.json 文件提供的常数值。

  1. private readonly MyOptions _snapshotOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #5: Snapshot options
  2. var snapshotOption1 = _snapshotOptions.Option1;
  3. var snapshotOption2 = _snapshotOptions.Option2;
  4. SnapshotOptions =
  5. $"snapshot option1 = {snapshotOption1}, " +
  6. $"snapshot option2 = {snapshotOption2}";

下图显示从 appsettings.json 文件加载的初始 option1option2 值:

  1. snapshot option1 = value1_from_json, snapshot option2 = -1

将 appsettings.json 文件中的值更改为 value1_from_json UPDATED200保存 appsettings.json 文件。刷新浏览器,查看更新的选项值:

  1. snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

包含 IConfigureNamedOptions 的命名选项支持Named options support with IConfigureNamedOptions

包含 IConfigureNamedOptions<TOptions> 的命名选项支持已作为示例 6 在示例应用中进行了演示。

命名选项支持允许应用在命名选项配置之间进行区分。在示例应用中,命名选项通过 OptionsServiceCollectionExtensions.Configure 进行声明,其调用扩展方法 ConfigureNamedOptions<TOptions>.Configure命名选项区分大小写。

  1. // Example #6: Named options (named_options_1)
  2. // Register the ConfigurationBuilder instance which MyOptions binds against.
  3. // Specify that the options loaded from configuration are named
  4. // "named_options_1".
  5. services.Configure<MyOptions>("named_options_1", Configuration);
  6. // Example #6: Named options (named_options_2)
  7. // Specify that the options loaded from the MyOptions class are named
  8. // "named_options_2".
  9. // Use a delegate to configure option values.
  10. services.Configure<MyOptions>("named_options_2", myOptions =>
  11. {
  12. myOptions.Option1 = "named_options_2_value1_from_action";
  13. });

示例应用通过 Get (Pages/Index.cshtml.cs ) 访问命名选项:

  1. private readonly MyOptions _named_options_1;
  2. private readonly MyOptions _named_options_2;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #6: Named options
  2. var named_options_1 =
  3. $"named_options_1: option1 = {_named_options_1.Option1}, " +
  4. $"option2 = {_named_options_1.Option2}";
  5. var named_options_2 =
  6. $"named_options_2: option1 = {_named_options_2.Option1}, " +
  7. $"option2 = {_named_options_2.Option2}";
  8. NamedOptions = $"{named_options_1} {named_options_2}";

运行示例应用,将返回命名选项:

  1. named_options_1: option1 = value1_from_json, option2 = -1
  2. named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

从配置中提供从 appsettings.json 文件中加载的 named_options_1 值。通过以下内容提供 named_options_2 值:

  • 针对 Option1ConfigureServices 中的 named_options_2 委托。
  • MyOptions 类提供的 Option2 的默认值。

使用 ConfigureAll 方法配置所有选项Configure all options with the ConfigureAll method

使用 ConfigureAll 方法配置所有选项实例。以下代码将针对包含公共值的所有配置实例配置 Option1将以下代码手动添加到 Startup.ConfigureServices 方法:

  1. services.ConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "ConfigureAll replacement value";
  4. });

添加代码后运行示例应用将产生以下结果:

  1. named_options_1: option1 = ConfigureAll replacement value, option2 = -1
  2. named_options_2: option1 = ConfigureAll replacement value, option2 = 5

备注

所有选项都是命名实例。现有 IConfigureOptions<TOptions> 实例将被视为面向为 string.EmptyOptions.DefaultName 实例。IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。null 命名选项用于面向所有命名实例而不是某一特定命名实例(ConfigureAllPostConfigureAll 使用此约定)。

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 用于配置 TOptions 实例。OptionsBuilder 简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName) 调用的单个参数,而不会出现在所有后续调用中。选项验证和接受服务依赖关系的 ConfigureOptions 重载仅可通过 OptionsBuilder 获得。

  1. // Options.DefaultName = "" is used.
  2. services.AddOptions<MyOptions>().Configure(o => o.Property = "default");
  3. services.AddOptions<MyOptions>("optionalName")
  4. .Configure(o => o.Property = "named");

使用 DI 服务配置选项Use DI services to configure options

在配置选项时,可以通过以下两种方式通过依赖关系注入访问其他服务:

  • 将配置委托传递给 OptionsBuilder 上的 ConfigureOptionsBuilder<TOptions> 提供 Configure 的重载,该重载允许使用最多五个服务来配置选项:
  1. services.AddOptions<MyOptions>("optionalName")
  2. .Configure<Service1, Service2, Service3, Service4, Service5>(
  3. (o, s, s2, s3, s4, s5) =>
  4. o.Property = DoSomethingWith(s, s2, s3, s4, s5));


建议将配置委托传递给 Configure,因为创建服务较复杂。在使用 Configure时,创建你自己的类型等效于框架为你执行的操作。调用 Configure 会注册临时泛型 IConfigureNamedOptions<TOptions>,它具有接受指定的泛型服务类型的构造函数。

选项验证Options validation

借助选项验证,可以验证已配置的选项。使用验证方法调用 Validate。如果选项有效,方法返回 true;如果无效,方法返回 false

  1. // Registration
  2. services.AddOptions<MyOptions>("optionalOptionsName")
  3. .Configure(o => { }) // Configure the options
  4. .Validate(o => YourValidationShouldReturnTrueIfValid(o),
  5. "custom error");
  6. // Consumption
  7. var monitor = services.BuildServiceProvider()
  8. .GetService<IOptionsMonitor<MyOptions>>();
  9. try
  10. {
  11. var options = monitor.Get("optionalOptionsName");
  12. }
  13. catch (OptionsValidationException e)
  14. {
  15. // e.OptionsName returns "optionalOptionsName"
  16. // e.OptionsType returns typeof(MyOptions)
  17. // e.Failures returns a list of errors, which would contain
  18. // "custom error"
  19. }

若要查看翻译为非英语语言的代码注释,请在 此 GitHub 讨论问题中告诉我们。

上面的示例将命名选项实例设置为 optionalOptionsName默认选项实例为 Options.DefaultName

选项验证在选项实例创建后运行。系统保证在选项实例首次获得访问时通过验证。

重要

选项验证无法防止在创建选项实例后发生选项修改。例如,在首次访问选项时按请求创建并验证 IOptionsSnapshot 选项。对于同一个请求,在后续访问尝试时不会再次验证 IOptionsSnapshot 选项 。

Validate 方法接受 Func<TOptions, bool>若要完全自定义验证,请实现 IValidateOptions<TOptions>,它支持:

  • 验证多种类型的选项:class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>
  • 验证取决于其他选项类型:public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)

IValidateOptions 验证:

  • 特定的命名选项实例。
  • 所有选项(如果 namenull 的话)。

通过接口实现返回 ValidateOptionsResult

  1. public interface IValidateOptions<TOptions> where TOptions : class
  2. {
  3. ValidateOptionsResult Validate(string name, TOptions options);
  4. }

通过调用 OptionsBuilder<TOptions> 上的 ValidateDataAnnotations 方法,可以从 Microsoft.Extensions.Options.DataAnnotations 包中获得基于数据注释的验证。Microsoft.Extensions.Options.DataAnnotations 已在 ASP.NET Core 应用中隐式引用。

  1. using System.ComponentModel.DataAnnotations;
  2. using Microsoft.Extensions.DependencyInjection;
  3. private class AnnotatedOptions
  4. {
  5. [Required]
  6. public string Required { get; set; }
  7. [StringLength(5, ErrorMessage = "Too long.")]
  8. public string StringLength { get; set; }
  9. [Range(-5, 5, ErrorMessage = "Out of range.")]
  10. public int IntRange { get; set; }
  11. }
  12. [Fact]
  13. public void CanValidateDataAnnotations()
  14. {
  15. var services = new ServiceCollection();
  16. services.AddOptions<AnnotatedOptions>()
  17. .Configure(o =>
  18. {
  19. o.StringLength = "111111";
  20. o.IntRange = 10;
  21. o.Custom = "nowhere";
  22. })
  23. .ValidateDataAnnotations();
  24. var sp = services.BuildServiceProvider();
  25. var error = Assert.Throws<OptionsValidationException>(() =>
  26. sp.GetRequiredService<IOptionsMonitor<AnnotatedOptions>>().CurrentValue);
  27. ValidateFailure<AnnotatedOptions>(error, Options.DefaultName, 1,
  28. "DataAnnotation validation failed for members Required " +
  29. "with the error 'The Required field is required.'.",
  30. "DataAnnotation validation failed for members StringLength " +
  31. "with the error 'Too long.'.",
  32. "DataAnnotation validation failed for members IntRange " +
  33. "with the error 'Out of range.'.");
  34. }

设计团队正在考虑为未来版本提供预先验证(在启动时快速失败)。

选项后期配置Options post-configuration

使用 IPostConfigureOptions<TOptions> 设置后期配置。进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:

  1. services.PostConfigure<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

PostConfigure 可用于对命名选项进行后期配置:

  1. services.PostConfigure<MyOptions>("named_options_1", myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

使用 PostConfigureAll 对所有配置实例进行后期配置:

  1. services.PostConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

在启动期间访问选项Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用于 Startup.Configure 中,因为在 Configure 方法执行之前已生成服务。

  1. public void Configure(IApplicationBuilder app,
  2. IOptionsMonitor<MyOptions> optionsAccessor)
  3. {
  4. var option1 = optionsAccessor.CurrentValue.Option1;
  5. }

不使用 Startup.ConfigureServices 中的 IOptions<TOptions>IOptionsMonitor<TOptions>由于服务注册的顺序,可能存在不一致的选项状态。

选项模式使用类来表示相关设置的组。配置设置由方案隔离到单独的类时,应用遵循两个重要软件工程原则:

选项还提供验证配置数据的机制。有关详细信息,请参阅选项验证部分。

查看或下载示例代码如何下载

先决条件Prerequisites

引用 Microsoft.AspNetCore.App 元包或将包引用添加到 Microsoft.Extensions.Options.ConfigurationExtensions 包。

选项接口Options interfaces

IOptionsMonitor<TOptions> 用于检索选项并管理 TOptions 实例的选项通知。IOptionsMonitor<TOptions> 支持以下方案:

IOptionsFactory<TOptions> 负责新建选项实例。它具有单个 Create 方法。默认实现采用所有已注册 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions> 并首先运行所有配置,然后才进行后期配置。它区分 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions> 且仅调用适当的接口。

IOptionsMonitorCache<TOptions>IOptionsMonitor<TOptions> 用于缓存 TOptions 实例。IOptionsMonitorCache<TOptions> 可使监视器中的选项实例无效,以便重新计算值 (TryRemove)。可以通过 TryAdd 手动引入值。在应按需重新创建所有命名实例时使用 Clear 方法。

IOptionsSnapshot<TOptions> 在每次请求时应重新计算选项的方案中有用。有关详细信息,请参阅通过 IOptionsSnapshot 重新加载配置数据部分。

IOptions<TOptions> 可用于支持选项。但是,IOptions<TOptions> 不支持前面的 IOptionsMonitor<TOptions> 方案。你可以在已使用 IOptions<TOptions> 接口的现有框架和库中继续使用 IOptions<TOptions>,并且不需要 IOptionsMonitor<TOptions> 提供的方案。

常规选项配置General options configuration

常规选项配置已作为示例 1 在示例应用中进行了演示。

选项类必须为包含公共无参数构造函数的非抽象类。以下类 MyOptions 具有两种属性:Option1Option2设置默认值为可选,但以下示例中的类构造函数设置了 Option1 的默认值。Option2 具有通过直接初始化属性设置的默认值 (Models/MyOptions.cs ):

  1. public class MyOptions
  2. {
  3. public MyOptions()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

MyOptions 类已通过 Configure 添加到服务容器并绑定到配置:

  1. // Example #1: General configuration
  2. // Register the Configuration instance which MyOptions binds against.
  3. services.Configure<MyOptions>(Configuration);

以下页面模型通过 IOptionsMonitor<TOptions> 使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs ):

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #1: Simple options
  2. var option1 = _options.Option1;
  3. var option2 = _options.Option2;
  4. SimpleOptions = $"option1 = {option1}, option2 = {option2}";

示例的 appsettings.json 文件指定 option1option2 的值:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Warning"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }

运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. option1 = value1_from_json, option2 = -1

备注

使用自定义 ConfigurationBuilder 从设置文件加载选项配置时,请确认基路径设置正确:

  1. var configBuilder = new ConfigurationBuilder()
  2. .SetBasePath(Directory.GetCurrentDirectory())
  3. .AddJsonFile("appsettings.json", optional: true);
  4. var config = configBuilder.Build();
  5. services.Configure<MyOptions>(config);

通过 CreateDefaultBuilder 从设置文件加载选项配置时,不需要显式设置基路径。

通过委托配置简单选项Configure simple options with a delegate

通过委托配置简单选项已作为示例 2 在示例应用中进行了演示。

使用委托设置选项值。此示例应用使用 MyOptionsWithDelegateConfig 类 (Models/MyOptionsWithDelegateConfig.cs ):

  1. public class MyOptionsWithDelegateConfig
  2. {
  3. public MyOptionsWithDelegateConfig()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

在以下代码中,已向服务容器添加第二个 IConfigureOptions<TOptions> 服务。它通过 MyOptionsWithDelegateConfig 使用委托来配置绑定:

  1. // Example #2: Options bound and configured by a delegate
  2. services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
  3. {
  4. myOptions.Option1 = "value1_configured_by_delegate";
  5. myOptions.Option2 = 500;
  6. });

Index.cshtml.cs :

  1. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #2: Options configured by delegate
  2. var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
  3. var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
  4. SimpleOptionsWithDelegateConfig =
  5. $"delegate_option1 = {delegate_config_option1}, " +
  6. $"delegate_option2 = {delegate_config_option2}";

可添加多个配置提供程序。配置提供程序可从 NuGet 包中获取,并按照注册的顺序应用。有关详细信息,请参阅 ASP.NET Core 中的配置

每次调用 Configure 都会将 IConfigureOptions<TOptions> 服务添加到服务容器。在前面的示例中,Option1Option2 的值同时在 appsettings.json 中指定,但 Option1Option2 的值被配置的委托替代。

当启用多个配置服务时,指定的最后一个配置源优于其他源 ,由其设置配置值。运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子选项配置Suboptions configuration

子选项配置已作为示例 3 在示例应用中进行了演示。

应用应创建适用于应用中特定方案组(类)的选项类。需要配置值的部分应用应仅有权访问其使用的配置值。

将选项绑定到配置时,选项类型中的每个属性都将绑定到窗体 property[:sub-property:] 的配置键。例如,MyOptions.Option1 属性将绑定到从 appsettings.json 中的 option1 属性读取的键 Option1

在以下代码中,已向服务容器添加第三个 IConfigureOptions<TOptions> 服务。它将 MySubOptions 绑定到 appsettings.json 文件的 subsection 部分:

  1. // Example #3: Suboptions
  2. // Bind options using a sub-section of the appsettings.json file.
  3. services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

GetSection 方法需要 Microsoft.Extensions.Configuration 命名空间。

示例的 appsettings.json 文件定义具有 suboption1suboption2 的键的 subsection 成员:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Warning"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }

MySubOptions 类将属性 SubOption1SubOption2 定义为保留选项值 (Models/MySubOptions.cs ):

  1. public class MySubOptions
  2. {
  3. public MySubOptions()
  4. {
  5. // Set default values.
  6. SubOption1 = "value1_from_ctor";
  7. SubOption2 = 5;
  8. }
  9. public string SubOption1 { get; set; }
  10. public int SubOption2 { get; set; }
  11. }

页面模型的 OnGet 方法返回包含选项值的字符串 (Pages/Index.cshtml.cs ):

  1. private readonly MySubOptions _subOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #3: Suboptions
  2. var subOption1 = _subOptions.SubOption1;
  3. var subOption2 = _subOptions.SubOption2;
  4. SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

运行应用时,OnGet 方法返回显示子选项类值的字符串:

  1. subOption1 = subvalue1_from_json, subOption2 = 200

选项注入Options injection

选项注入已作为示例 4 在示例应用中进行了演示。

IOptionsMonitor<TOptions> 注入:

  • 使用 @inject Razor 指令的 Razor 页面或 MVC 视图。
  • 页面或视图模型。

示例应用中的以下示例将 IOptionsMonitor<TOptions> 注入页面模型 (Pages/Index.cshtml.cs):

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #4: Bind options directly to the page
  2. MyOptions = _options;

示例应用演示如何使用 @inject 指令注入 IOptionsMonitor<MyOptions>

  1. @page
  2. @model IndexModel
  3. @using Microsoft.Extensions.Options
  4. @inject IOptionsMonitor<MyOptions> OptionsAccessor
  5. @{
  6. ViewData["Title"] = "Options Sample";
  7. }
  8. <h1>@ViewData["Title"]</h1>

当应用运行时,选项值显示在呈现的页面中:

选项值 Option1:value1_from_json 和 Option2:-1 从模型中加载并注入视图。

通过 IOptionsSnapshot 重新加载配置数据Reload configuration data with IOptionsSnapshot

通过 IOptionsSnapshot<TOptions> 重新加载配置数据已作为示例 5 在示例应用中进行了演示。

通过使用 IOptionsSnapshot<TOptions>,针对请求生存期访问和缓存选项时,每个请求都会计算一次选项。

IOptionsMonitorIOptionsSnapshot 之间的区别在于:

  • IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。
  • IOptionsSnapshot 是一种作用域服务,并在构造 IOptionsSnapshot<T> 对象时提供选项的快照。选项快照旨在用于暂时性和有作用域的依赖项。

以下示例演示如何在更改 appsettings.json (Pages/Index.cshtml.cs ) 后创建新的 IOptionsSnapshot<TOptions>在更改文件和重新加载配置之前,针对服务器的多个请求返回 appsettings.json 文件提供的常数值。

  1. private readonly MyOptions _snapshotOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #5: Snapshot options
  2. var snapshotOption1 = _snapshotOptions.Option1;
  3. var snapshotOption2 = _snapshotOptions.Option2;
  4. SnapshotOptions =
  5. $"snapshot option1 = {snapshotOption1}, " +
  6. $"snapshot option2 = {snapshotOption2}";

下图显示从 appsettings.json 文件加载的初始 option1option2 值:

  1. snapshot option1 = value1_from_json, snapshot option2 = -1

将 appsettings.json 文件中的值更改为 value1_from_json UPDATED200保存 appsettings.json 文件。刷新浏览器,查看更新的选项值:

  1. snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

包含 IConfigureNamedOptions 的命名选项支持Named options support with IConfigureNamedOptions

包含 IConfigureNamedOptions<TOptions> 的命名选项支持已作为示例 6 在示例应用中进行了演示。

命名选项支持允许应用在命名选项配置之间进行区分。在示例应用中,命名选项通过 OptionsServiceCollectionExtensions.Configure 进行声明,其调用扩展方法 ConfigureNamedOptions<TOptions>.Configure命名选项区分大小写。

  1. // Example #6: Named options (named_options_1)
  2. // Register the ConfigurationBuilder instance which MyOptions binds against.
  3. // Specify that the options loaded from configuration are named
  4. // "named_options_1".
  5. services.Configure<MyOptions>("named_options_1", Configuration);
  6. // Example #6: Named options (named_options_2)
  7. // Specify that the options loaded from the MyOptions class are named
  8. // "named_options_2".
  9. // Use a delegate to configure option values.
  10. services.Configure<MyOptions>("named_options_2", myOptions =>
  11. {
  12. myOptions.Option1 = "named_options_2_value1_from_action";
  13. });

示例应用通过 Get (Pages/Index.cshtml.cs ) 访问命名选项:

  1. private readonly MyOptions _named_options_1;
  2. private readonly MyOptions _named_options_2;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #6: Named options
  2. var named_options_1 =
  3. $"named_options_1: option1 = {_named_options_1.Option1}, " +
  4. $"option2 = {_named_options_1.Option2}";
  5. var named_options_2 =
  6. $"named_options_2: option1 = {_named_options_2.Option1}, " +
  7. $"option2 = {_named_options_2.Option2}";
  8. NamedOptions = $"{named_options_1} {named_options_2}";

运行示例应用,将返回命名选项:

  1. named_options_1: option1 = value1_from_json, option2 = -1
  2. named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

从配置中提供从 appsettings.json 文件中加载的 named_options_1 值。通过以下内容提供 named_options_2 值:

  • 针对 Option1ConfigureServices 中的 named_options_2 委托。
  • MyOptions 类提供的 Option2 的默认值。

使用 ConfigureAll 方法配置所有选项Configure all options with the ConfigureAll method

使用 ConfigureAll 方法配置所有选项实例。以下代码将针对包含公共值的所有配置实例配置 Option1将以下代码手动添加到 Startup.ConfigureServices 方法:

  1. services.ConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "ConfigureAll replacement value";
  4. });

添加代码后运行示例应用将产生以下结果:

  1. named_options_1: option1 = ConfigureAll replacement value, option2 = -1
  2. named_options_2: option1 = ConfigureAll replacement value, option2 = 5

备注

所有选项都是命名实例。现有 IConfigureOptions<TOptions> 实例将被视为面向为 string.EmptyOptions.DefaultName 实例。IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。null 命名选项用于面向所有命名实例而不是某一特定命名实例(ConfigureAllPostConfigureAll 使用此约定)。

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 用于配置 TOptions 实例。OptionsBuilder 简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName) 调用的单个参数,而不会出现在所有后续调用中。选项验证和接受服务依赖关系的 ConfigureOptions 重载仅可通过 OptionsBuilder 获得。

  1. // Options.DefaultName = "" is used.
  2. services.AddOptions<MyOptions>().Configure(o => o.Property = "default");
  3. services.AddOptions<MyOptions>("optionalName")
  4. .Configure(o => o.Property = "named");

使用 DI 服务配置选项Use DI services to configure options

在配置选项时,可以通过以下两种方式通过依赖关系注入访问其他服务:

  1. services.AddOptions<MyOptions>("optionalName")
  2. .Configure<Service1, Service2, Service3, Service4, Service5>(
  3. (o, s, s2, s3, s4, s5) =>
  4. o.Property = DoSomethingWith(s, s2, s3, s4, s5));


建议将配置委托传递给 Configure,因为创建服务较复杂。在使用 Configure时,创建你自己的类型等效于框架为你执行的操作。调用 Configure 会注册临时泛型 IConfigureNamedOptions<TOptions>,它具有接受指定的泛型服务类型的构造函数。

选项验证Options validation

借助选项验证,可以验证已配置的选项。使用验证方法调用 Validate。如果选项有效,方法返回 true;如果无效,方法返回 false

  1. // Registration
  2. services.AddOptions<MyOptions>("optionalOptionsName")
  3. .Configure(o => { }) // Configure the options
  4. .Validate(o => YourValidationShouldReturnTrueIfValid(o),
  5. "custom error");
  6. // Consumption
  7. var monitor = services.BuildServiceProvider()
  8. .GetService<IOptionsMonitor<MyOptions>>();
  9. try
  10. {
  11. var options = monitor.Get("optionalOptionsName");
  12. }
  13. catch (OptionsValidationException e)
  14. {
  15. // e.OptionsName returns "optionalOptionsName"
  16. // e.OptionsType returns typeof(MyOptions)
  17. // e.Failures returns a list of errors, which would contain
  18. // "custom error"
  19. }

上面的示例将命名选项实例设置为 optionalOptionsName默认选项实例为 Options.DefaultName

选项验证在选项实例创建后运行。系统保证在选项实例首次获得访问时通过验证。

重要

选项验证无法防止在创建选项实例后发生选项修改。例如,在首次访问选项时按请求创建并验证 IOptionsSnapshot 选项。对于同一个请求,在后续访问尝试时不会再次验证 IOptionsSnapshot 选项 。

Validate 方法接受 Func<TOptions, bool>若要完全自定义验证,请实现 IValidateOptions<TOptions>,它支持:

  • 验证多种类型的选项:class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>
  • 验证取决于其他选项类型:public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)

IValidateOptions 验证:

  • 特定的命名选项实例。
  • 所有选项(如果 namenull 的话)。

通过接口实现返回 ValidateOptionsResult

  1. public interface IValidateOptions<TOptions> where TOptions : class
  2. {
  3. ValidateOptionsResult Validate(string name, TOptions options);
  4. }

通过调用 OptionsBuilder<TOptions> 上的 ValidateDataAnnotations 方法,可以从 Microsoft.Extensions.Options.DataAnnotations 包中获得基于数据注释的验证。Microsoft.Extensions.Options.DataAnnotations 包含在 Microsoft.AspNetCore.App 元包中。

  1. using Microsoft.Extensions.DependencyInjection;
  2. private class AnnotatedOptions
  3. {
  4. [Required]
  5. public string Required { get; set; }
  6. [StringLength(5, ErrorMessage = "Too long.")]
  7. public string StringLength { get; set; }
  8. [Range(-5, 5, ErrorMessage = "Out of range.")]
  9. public int IntRange { get; set; }
  10. }
  11. [Fact]
  12. public void CanValidateDataAnnotations()
  13. {
  14. var services = new ServiceCollection();
  15. services.AddOptions<AnnotatedOptions>()
  16. .Configure(o =>
  17. {
  18. o.StringLength = "111111";
  19. o.IntRange = 10;
  20. o.Custom = "nowhere";
  21. })
  22. .ValidateDataAnnotations();
  23. var sp = services.BuildServiceProvider();
  24. var error = Assert.Throws<OptionsValidationException>(() =>
  25. sp.GetRequiredService<IOptionsMonitor<AnnotatedOptions>>().CurrentValue);
  26. ValidateFailure<AnnotatedOptions>(error, Options.DefaultName, 1,
  27. "DataAnnotation validation failed for members Required " +
  28. "with the error 'The Required field is required.'.",
  29. "DataAnnotation validation failed for members StringLength " +
  30. "with the error 'Too long.'.",
  31. "DataAnnotation validation failed for members IntRange " +
  32. "with the error 'Out of range.'.");
  33. }

设计团队正在考虑为未来版本提供预先验证(在启动时快速失败)。

选项后期配置Options post-configuration

使用 IPostConfigureOptions<TOptions> 设置后期配置。进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:

  1. services.PostConfigure<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

PostConfigure 可用于对命名选项进行后期配置:

  1. services.PostConfigure<MyOptions>("named_options_1", myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

使用 PostConfigureAll 对所有配置实例进行后期配置:

  1. services.PostConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

在启动期间访问选项Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用于 Startup.Configure 中,因为在 Configure 方法执行之前已生成服务。

  1. public void Configure(IApplicationBuilder app, IOptionsMonitor<MyOptions> optionsAccessor)
  2. {
  3. var option1 = optionsAccessor.CurrentValue.Option1;
  4. }

不使用 Startup.ConfigureServices 中的 IOptions<TOptions>IOptionsMonitor<TOptions>由于服务注册的顺序,可能存在不一致的选项状态。

选项模式使用类来表示相关设置的组。配置设置由方案隔离到单独的类时,应用遵循两个重要软件工程原则:

选项还提供验证配置数据的机制。有关详细信息,请参阅选项验证部分。

查看或下载示例代码如何下载

先决条件Prerequisites

引用 Microsoft.AspNetCore.App 元包或将包引用添加到 Microsoft.Extensions.Options.ConfigurationExtensions 包。

选项接口Options interfaces

IOptionsMonitor<TOptions> 用于检索选项并管理 TOptions 实例的选项通知。IOptionsMonitor<TOptions> 支持以下方案:

IOptionsFactory<TOptions> 负责新建选项实例。它具有单个 Create 方法。默认实现采用所有已注册 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions> 并首先运行所有配置,然后才进行后期配置。它区分 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions> 且仅调用适当的接口。

IOptionsMonitorCache<TOptions>IOptionsMonitor<TOptions> 用于缓存 TOptions 实例。IOptionsMonitorCache<TOptions> 可使监视器中的选项实例无效,以便重新计算值 (TryRemove)。可以通过 TryAdd 手动引入值。在应按需重新创建所有命名实例时使用 Clear 方法。

IOptionsSnapshot<TOptions> 在每次请求时应重新计算选项的方案中有用。有关详细信息,请参阅通过 IOptionsSnapshot 重新加载配置数据部分。

IOptions<TOptions> 可用于支持选项。但是,IOptions<TOptions> 不支持前面的 IOptionsMonitor<TOptions> 方案。你可以在已使用 IOptions<TOptions> 接口的现有框架和库中继续使用 IOptions<TOptions>,并且不需要 IOptionsMonitor<TOptions> 提供的方案。

常规选项配置General options configuration

常规选项配置已作为示例 1 在示例应用中进行了演示。

选项类必须为包含公共无参数构造函数的非抽象类。以下类 MyOptions 具有两种属性:Option1Option2设置默认值为可选,但以下示例中的类构造函数设置了 Option1 的默认值。Option2 具有通过直接初始化属性设置的默认值 (Models/MyOptions.cs ):

  1. public class MyOptions
  2. {
  3. public MyOptions()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

MyOptions 类已通过 Configure 添加到服务容器并绑定到配置:

  1. // Example #1: General configuration
  2. // Register the Configuration instance which MyOptions binds against.
  3. services.Configure<MyOptions>(Configuration);

以下页面模型通过 IOptionsMonitor<TOptions> 使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs ):

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #1: Simple options
  2. var option1 = _options.Option1;
  3. var option2 = _options.Option2;
  4. SimpleOptions = $"option1 = {option1}, option2 = {option2}";

示例的 appsettings.json 文件指定 option1option2 的值:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Warning"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }

运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. option1 = value1_from_json, option2 = -1

备注

使用自定义 ConfigurationBuilder 从设置文件加载选项配置时,请确认基路径设置正确:

  1. var configBuilder = new ConfigurationBuilder()
  2. .SetBasePath(Directory.GetCurrentDirectory())
  3. .AddJsonFile("appsettings.json", optional: true);
  4. var config = configBuilder.Build();
  5. services.Configure<MyOptions>(config);

通过 CreateDefaultBuilder 从设置文件加载选项配置时,不需要显式设置基路径。

通过委托配置简单选项Configure simple options with a delegate

通过委托配置简单选项已作为示例 2 在示例应用中进行了演示。

使用委托设置选项值。此示例应用使用 MyOptionsWithDelegateConfig 类 (Models/MyOptionsWithDelegateConfig.cs ):

  1. public class MyOptionsWithDelegateConfig
  2. {
  3. public MyOptionsWithDelegateConfig()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = 5;
  10. }

在以下代码中,已向服务容器添加第二个 IConfigureOptions<TOptions> 服务。它通过 MyOptionsWithDelegateConfig 使用委托来配置绑定:

  1. // Example #2: Options bound and configured by a delegate
  2. services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
  3. {
  4. myOptions.Option1 = "value1_configured_by_delegate";
  5. myOptions.Option2 = 500;
  6. });

Index.cshtml.cs :

  1. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #2: Options configured by delegate
  2. var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
  3. var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
  4. SimpleOptionsWithDelegateConfig =
  5. $"delegate_option1 = {delegate_config_option1}, " +
  6. $"delegate_option2 = {delegate_config_option2}";

可添加多个配置提供程序。配置提供程序可从 NuGet 包中获取,并按照注册的顺序应用。有关详细信息,请参阅 ASP.NET Core 中的配置

每次调用 Configure 都会将 IConfigureOptions<TOptions> 服务添加到服务容器。在前面的示例中,Option1Option2 的值同时在 appsettings.json 中指定,但 Option1Option2 的值被配置的委托替代。

当启用多个配置服务时,指定的最后一个配置源优于其他源 ,由其设置配置值。运行应用时,页面模型的 OnGet 方法返回显示选项类值的字符串:

  1. delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子选项配置Suboptions configuration

子选项配置已作为示例 3 在示例应用中进行了演示。

应用应创建适用于应用中特定方案组(类)的选项类。需要配置值的部分应用应仅有权访问其使用的配置值。

将选项绑定到配置时,选项类型中的每个属性都将绑定到窗体 property[:sub-property:] 的配置键。例如,MyOptions.Option1 属性将绑定到从 appsettings.json 中的 option1 属性读取的键 Option1

在以下代码中,已向服务容器添加第三个 IConfigureOptions<TOptions> 服务。它将 MySubOptions 绑定到 appsettings.json 文件的 subsection 部分:

  1. // Example #3: Suboptions
  2. // Bind options using a sub-section of the appsettings.json file.
  3. services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

GetSection 方法需要 Microsoft.Extensions.Configuration 命名空间。

示例的 appsettings.json 文件定义具有 suboption1suboption2 的键的 subsection 成员:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -1,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2": 200
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Warning"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }

MySubOptions 类将属性 SubOption1SubOption2 定义为保留选项值 (Models/MySubOptions.cs ):

  1. public class MySubOptions
  2. {
  3. public MySubOptions()
  4. {
  5. // Set default values.
  6. SubOption1 = "value1_from_ctor";
  7. SubOption2 = 5;
  8. }
  9. public string SubOption1 { get; set; }
  10. public int SubOption2 { get; set; }
  11. }

页面模型的 OnGet 方法返回包含选项值的字符串 (Pages/Index.cshtml.cs ):

  1. private readonly MySubOptions _subOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #3: Suboptions
  2. var subOption1 = _subOptions.SubOption1;
  3. var subOption2 = _subOptions.SubOption2;
  4. SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

运行应用时,OnGet 方法返回显示子选项类值的字符串:

  1. subOption1 = subvalue1_from_json, subOption2 = 200

视图模型或通过直接视图注入提供的选项Options provided by a view model or with direct view injection

视图模型或通过直接视图注入提供的选项已作为示例 4 在示例应用中进行了演示。

可在视图模型中或通过将 IOptionsMonitor<TOptions> 直接注入到视图 (Pages/Index.cshtml.cs ) 来提供选项:

  1. private readonly MyOptions _options;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #4: Bind options directly to the page
  2. MyOptions = _options;

示例应用演示如何使用 @inject 指令注入 IOptionsMonitor<MyOptions>

  1. @page
  2. @model IndexModel
  3. @using Microsoft.Extensions.Options
  4. @inject IOptionsMonitor<MyOptions> OptionsAccessor
  5. @{
  6. ViewData["Title"] = "Options Sample";
  7. }
  8. <h1>@ViewData["Title"]</h1>

当应用运行时,选项值显示在呈现的页面中:

选项值 Option1:value1_from_json 和 Option2:-1 从模型中加载并注入视图。

通过 IOptionsSnapshot 重新加载配置数据Reload configuration data with IOptionsSnapshot

通过 IOptionsSnapshot<TOptions> 重新加载配置数据已作为示例 5 在示例应用中进行了演示。

IOptionsSnapshot<TOptions> 支持包含最小处理开销的重新加载选项。

针对请求生存期访问和缓存选项时,每个请求只能计算一次选项。

以下示例演示如何在更改 appsettings.json (Pages/Index.cshtml.cs ) 后创建新的 IOptionsSnapshot<TOptions>在更改文件和重新加载配置之前,针对服务器的多个请求返回 appsettings.json 文件提供的常数值。

  1. private readonly MyOptions _snapshotOptions;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #5: Snapshot options
  2. var snapshotOption1 = _snapshotOptions.Option1;
  3. var snapshotOption2 = _snapshotOptions.Option2;
  4. SnapshotOptions =
  5. $"snapshot option1 = {snapshotOption1}, " +
  6. $"snapshot option2 = {snapshotOption2}";

下图显示从 appsettings.json 文件加载的初始 option1option2 值:

  1. snapshot option1 = value1_from_json, snapshot option2 = -1

将 appsettings.json 文件中的值更改为 value1_from_json UPDATED200保存 appsettings.json 文件。刷新浏览器,查看更新的选项值:

  1. snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

包含 IConfigureNamedOptions 的命名选项支持Named options support with IConfigureNamedOptions

包含 IConfigureNamedOptions<TOptions> 的命名选项支持已作为示例 6 在示例应用中进行了演示。

命名选项支持允许应用在命名选项配置之间进行区分。在示例应用中,命名选项通过 OptionsServiceCollectionExtensions.Configure 进行声明,其调用扩展方法 ConfigureNamedOptions<TOptions>.Configure命名选项区分大小写。

  1. // Example #6: Named options (named_options_1)
  2. // Register the ConfigurationBuilder instance which MyOptions binds against.
  3. // Specify that the options loaded from configuration are named
  4. // "named_options_1".
  5. services.Configure<MyOptions>("named_options_1", Configuration);
  6. // Example #6: Named options (named_options_2)
  7. // Specify that the options loaded from the MyOptions class are named
  8. // "named_options_2".
  9. // Use a delegate to configure option values.
  10. services.Configure<MyOptions>("named_options_2", myOptions =>
  11. {
  12. myOptions.Option1 = "named_options_2_value1_from_action";
  13. });

示例应用通过 Get (Pages/Index.cshtml.cs ) 访问命名选项:

  1. private readonly MyOptions _named_options_1;
  2. private readonly MyOptions _named_options_2;
  1. public IndexModel(
  2. IOptionsMonitor<MyOptions> optionsAccessor,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MySubOptions> subOptionsAccessor,
  5. IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
  6. IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  7. {
  8. _options = optionsAccessor.CurrentValue;
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _subOptions = subOptionsAccessor.CurrentValue;
  11. _snapshotOptions = snapshotOptionsAccessor.Value;
  12. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  13. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  14. }
  1. // Example #6: Named options
  2. var named_options_1 =
  3. $"named_options_1: option1 = {_named_options_1.Option1}, " +
  4. $"option2 = {_named_options_1.Option2}";
  5. var named_options_2 =
  6. $"named_options_2: option1 = {_named_options_2.Option1}, " +
  7. $"option2 = {_named_options_2.Option2}";
  8. NamedOptions = $"{named_options_1} {named_options_2}";

运行示例应用,将返回命名选项:

  1. named_options_1: option1 = value1_from_json, option2 = -1
  2. named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

从配置中提供从 appsettings.json 文件中加载的 named_options_1 值。通过以下内容提供 named_options_2 值:

  • 针对 Option1ConfigureServices 中的 named_options_2 委托。
  • MyOptions 类提供的 Option2 的默认值。

使用 ConfigureAll 方法配置所有选项Configure all options with the ConfigureAll method

使用 ConfigureAll 方法配置所有选项实例。以下代码将针对包含公共值的所有配置实例配置 Option1将以下代码手动添加到 Startup.ConfigureServices 方法:

  1. services.ConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "ConfigureAll replacement value";
  4. });

添加代码后运行示例应用将产生以下结果:

  1. named_options_1: option1 = ConfigureAll replacement value, option2 = -1
  2. named_options_2: option1 = ConfigureAll replacement value, option2 = 5

备注

所有选项都是命名实例。现有 IConfigureOptions<TOptions> 实例将被视为面向为 string.EmptyOptions.DefaultName 实例。IConfigureNamedOptions<TOptions> 还可实现 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的默认实现具有适当地使用每个实例的逻辑。null 命名选项用于面向所有命名实例而不是某一特定命名实例(ConfigureAllPostConfigureAll 使用此约定)。

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 用于配置 TOptions 实例。OptionsBuilder 简化了创建命名选项的过程,因为它只是初始 AddOptions<TOptions>(string optionsName) 调用的单个参数,而不会出现在所有后续调用中。选项验证和接受服务依赖关系的 ConfigureOptions 重载仅可通过 OptionsBuilder 获得。

  1. // Options.DefaultName = "" is used.
  2. services.AddOptions<MyOptions>().Configure(o => o.Property = "default");
  3. services.AddOptions<MyOptions>("optionalName")
  4. .Configure(o => o.Property = "named");

使用 DI 服务配置选项Use DI services to configure options

在配置选项时,可以通过以下两种方式通过依赖关系注入访问其他服务:

  1. services.AddOptions<MyOptions>("optionalName")
  2. .Configure<Service1, Service2, Service3, Service4, Service5>(
  3. (o, s, s2, s3, s4, s5) =>
  4. o.Property = DoSomethingWith(s, s2, s3, s4, s5));


建议将配置委托传递给 Configure,因为创建服务较复杂。在使用 Configure时,创建你自己的类型等效于框架为你执行的操作。调用 Configure 会注册临时泛型 IConfigureNamedOptions<TOptions>,它具有接受指定的泛型服务类型的构造函数。

选项后期配置Options post-configuration

使用 IPostConfigureOptions<TOptions> 设置后期配置。进行所有 IConfigureOptions<TOptions> 配置后运行后期配置:

  1. services.PostConfigure<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

PostConfigure 可用于对命名选项进行后期配置:

  1. services.PostConfigure<MyOptions>("named_options_1", myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

使用 PostConfigureAll 对所有配置实例进行后期配置:

  1. services.PostConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "post_configured_option1_value";
  4. });

在启动期间访问选项Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用于 Startup.Configure 中,因为在 Configure 方法执行之前已生成服务。

  1. public void Configure(IApplicationBuilder app, IOptionsMonitor<MyOptions> optionsAccessor)
  2. {
  3. var option1 = optionsAccessor.CurrentValue.Option1;
  4. }

不使用 Startup.ConfigureServices 中的 IOptions<TOptions>IOptionsMonitor<TOptions>由于服务注册的顺序,可能存在不一致的选项状态。

其他资源Additional resources