一. 概述
本章讲的选项模式是对 Configuration 配置的功能扩展. 讲这篇时有个专用名词叫 "选项类 (TOptions)" . 该选项类作用是指: 把选项类中的属性与配置来源中的键关联起来. 举个例, 假设 JSON 文件有个 Option1 键, 选项类中也有个叫 Option1 的属性名, 经过选项配置, 这样就能把 JSON 中的键的值映射到选项类属性值中. 也可以理解在项目应用中, 把一个 JSON 文件序列化到. net 类.
1.1 选项接口介绍
在官方文档中选项接口有很多, 这里列举了这些选项接口. 所有选项接口基本都继承了 TOptions 接口.
- // Used for notifications when TOptions instances change
- public interface IOptionsMonitor<out TOptions>
- {
- //
- // 摘要:
- // Returns the current TOptions instance with the Microsoft.Extensions.Options.Options.DefaultName.
- TOptions CurrentValue { get; }
- //...
- }
- // Used to create TOptions instances
- public interface IOptionsFactory<TOptions> where TOptions : class, new()
- {
- //
- // 摘要:
- // Returns a configured TOptions instance with the given name.
- TOptions Create(string name);
- }
- // Represents something that configures the TOptions type. Note: These are run before all
- public interface IConfigureOptions<in TOptions> where TOptions : class
- {
- //
- // 摘要:
- // Invoked to configure a TOptions instance.
- //
- // 参数:
- // options:
- // The options instance to configure.
- void Configure(TOptions options);
- }
- public interface IPostConfigureOptions<in TOptions> where TOptions : class
- {
- //
- // 摘要:
- // Invoked to configure a TOptions instance.
- //
- // 参数:
- // name:
- // The name of the options instance being configured.
- //
- // options:
- // The options instance to configured.
- void PostConfigure(string name, TOptions options);
- }
- public interface IConfigureNamedOptions<in TOptions> : IConfigureOptions<TOptions> where TOptions : class
- {
- //
- // 摘要:
- // Invoked to configure a TOptions instance.
- //
- // 参数:
- // name:
- // The name of the options instance being configured.
- //
- // options:
- // The options instance to configure.
- void Configure(string name, TOptions options);
- }
- // Used by IOptionsMonitor<TOptions> to cache TOptions instances.
- public interface IOptionsMonitorCache<TOptions> where TOptions : class
- {
- //
- // 摘要:
- // Clears all options instances from the cache.
- void Clear();
- //
- // 摘要:
- // Gets a named options instance, or adds a new instance created with createOptions.
- //
- // 参数:
- // name:
- // The name of the options instance.
- //
- // createOptions:
- // The func used to create the new instance.
- //
- // 返回结果:
- // The options instance.
- TOptions GetOrAdd(string name, Func<TOptions> createOptions);
- //
- // 摘要:
- // Tries to adds a new option to the cache, will return false if the name already
- // exists.
- //
- // 参数:
- // name:
- // The name of the options instance.
- //
- // options:
- // The options instance.
- //
- // 返回结果:
- // Whether anything was added.
- bool TryAdd(string name, TOptions options);
- //
- // 摘要:
- // Try to remove an options instance.
- //
- // 参数:
- // name:
- // The name of the options instance.
- //
- // 返回结果:
- // Whether anything was removed.
- bool TryRemove(string name);
- }
- // Used to access the value of TOptions for the lifetime of a request
- public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
- {
- //
- // 摘要:
- // Returns a configured TOptions instance with the given name.
- TOptions Get(string name);
- }
- //Used to retrieve configured TOptions instances
- public interface IOptions<out TOptions> where TOptions : class, new()
- {
- //
- // 摘要:
- // The default configured TOptions instance
- TOptions Value { get; }
- }
- View Code
- (1) IOptionsMonitor<TOptions>
IOptionsMonitor<TOptions > 用于 TOptions 实例更改时的通知, 用于管理 TOptions 选项类 . 该 IOptionsMonitor<TOptions > 支持以下方案:
(1) 更改通知. 当配置文件发生修改时, 会监听同步到选项类.
(2) 命名选项. IConfigureNamedOptions 支持命名选项. 接口继续关系 IConfigureNamedOptions:IConfigureOptions
(3) 重新加载配置. 通过 IOptionsSnapshot 重新加载配置数据, IOptionsMonitor 也支持该功能. 接口继续关系 IOptionsSnapshot :IOptions
(4) 选择性选项失效 (IOptionsMonitorCache<TOptions>).
(2) 其它接口
IOptionsFactory<TOptions> 负责产生 TOptions 选项实例, 它具有单个 Create 方法.
默认实现采用所有已注册 IConfigureOptions<TOptions> 和 IPostConfigureOptions<TOptions> 并首先运行所有配置 (所有的来源配置),
然后才进行选项后期配置 IPostConfigureOptions<TOptions> .
IOptionsMonitorCache<TOptions > 用于缓存 TOptions 实例.
1.2 常规选项配置
TOptions 选项类必须为包含公共无参数构造函数的非抽象类. 下面示例中选项类 MyOptions 具有两种属性: Option1 和 Option2. 设置默认值为可选, 但以下示例中的类构造函数设置了 Option1 的默认值. Option2 具有通过直接初始化属性设置的默认值.
- public class MyOptions
- {
- public MyOptions()
- {
- // Set default value.
- Option1 = "value1_from_ctor";
- }
- public string Option1 { get; set; }
- public int Option2 { get; set; } = 5;
- }
- // 将 MyOptions 类已通过 Configure 添加到服务容器, 并绑定到配置 IConfiguration 上
- //Registers a configuration instance which TOptions will bind against.
- services.Configure<MyOptions>(Configuration);
- private readonly MyOptions _options;
- //OtherPages/Page1
- public Page1Model( IOptionsMonitor<MyOptions> optionsAccessor)
- {
- _options = optionsAccessor.CurrentValue;
- }
- public void OnGet() {
- var option1 = _options.Option1;
- var option2 = _options.Option2;
- var SimpleOptions = $"option1 = {option1}, option2 = {option2}";
- }
- // 此时 SimpleOptions 值:"option1 = value1_from_ctor, option2 = 5"
- // 下面在 appsettings.JSON 文件添加 option1 和 option2 的值.
- "option1": "value1_from_json",
- "option2": -1,
当配置文件 appsettings.JSON 中 option1 和 option2 键的值改变后, MyOptions 选项类中的属性 option1 和 option2 的值也会改变. 下面再次运行 OtherPages/Page1
// 此时 SimpleOptions 的值为:"option1 = value1_from_json, option2 = -1"
为什么 MyOptions 类中 option1,option2 会取到 appsettings.JSON 文件中的值呢? 因为 MyOptions 选项类注入到 Iconfiguration 服务后与 appsettings.JSON 文件中键相同, 形成了映射.
1.3 通过委托配置简单选项
使用委托设置选项值. 此示例应用使用 MyOptionsWithDelegateConfig 类 , 这里仍然是使用相同的键 Option1,Option2. 它通过 MyOptionsWithDelegateConfig 使用委托来配置绑定.
- public class MyOptionsWithDelegateConfig
- {
- public MyOptionsWithDelegateConfig()
- {
- // Set default value.
- Option1 = "value1_from_ctor";
- }
- public string Option1 { get; set; }
- public int Option2 { get; set; } = 5;
- }
- services.Configure<MyOptions>(Configuration);
- // 第二个注入服务
- services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
- {
- // 在 Page1Model 构造方法中生成 MyOptionsWithDelegateConfig 实例时调用
- myOptions.Option1 = "value1_configured_by_delegate";
- myOptions.Option2 = 500;
- });
- public Page1Model(
- IConfiguration configuration,
- IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
- IOptionsMonitor<MyOptions> optionsAccessor
- )
- {
- _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
- _options = optionsAccessor.CurrentValue;
- Configuration = configuration;
- }
- public IConfiguration Configuration { get; }
- private readonly MyOptions _options;
- private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
- public string BindGUIDMsg { get; set; }
- public void OnGet()
- {
- BindGUIDMsg = $"option1 = {_options.Option1}, option2 = {_options.Option2}";
- BindGUIDMsg += "</br>";
- BindGUIDMsg += $"delegate_option1 = {_optionsWithDelegateConfig.Option1}," +
- $"delegate_option2 = {_optionsWithDelegateConfig.Option2}";
- }
每次调用 Configure 都会将 IConfigureOptions<TOptions> 服务添加到服务容器. 在前面的示例中, Option1 和 Option2 的值同时在 appsettings.JSON 中指定, 但 Option1 和 Option2 的值被配置的委托替代.
当启用多个配置服务时, 指定的最后一个配置源优于其他源, 由其设置配置值. 运行应用时, 页面模型的 OnGet 方法返回显示选项类值的字符串:
- // myOptions 实例取值如下:
- SimpleOptions:option1 = -1,option2 = 5
- // MyOptionsWithDelegateConfig 实例取值如下:
- delegate_option1 = value1_configured_by_delegate,delegate_option2 = 500
1.4 子选项配置
当配置文件中的子节点需要与选项类进行关联映射时, 可以通过服务注入 bind 到指定的 Configuration 节点. 在以下代码中, 已向服务容器添加第三个 IConfigureOptions<TOptions> 服务. 它将 MySubOptions 绑定到 appsettings.JSON 文件的 subsection 部分:
- "Option1": "value1_from_json",
- "Option2": -1,
- "subsection": {
- "suboption1": "subvalue1_from_json",
- "suboption2": 200
- }
- public class MySubOptions
- {
- public MySubOptions()
- {
- // Set default values.
- SubOption1 = "value1_from_ctor";
- SubOption2 = 5;
- }
- public string SubOption1 { get; set; }
- public int SubOption2 { get; set; }
- }
- // 第三个 IConfigureOptions<TOptions > 注入服务
- services.Configure<MySubOptions>(Configuration.GetSection("subsection"));
- //OtherPages/Page1
- public Page1Model(
- IConfiguration configuration,
- IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
- IOptionsMonitor<MyOptions> optionsAccessor,
- IOptionsMonitor<MySubOptions> subOptionsAccessor
- )
- {
- _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
- _options = optionsAccessor.CurrentValue;
- _subOptions = subOptionsAccessor.CurrentValue;
- Configuration = configuration;
- }
- public IConfiguration Configuration { get; }
- private readonly MyOptions _options;
- private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
- private readonly MySubOptions _subOptions;
- // OnGet 方法
- SubOptions = $"subOption1 = {_subOptions.SubOption1}, subOption2 = {_subOptions.SubOption2}"
- // 运行应用时, OnGet 方法返回显示子选项类值的字符串:
- // MySubOptions 实例取值如下:
- subOption1 = subvalue1_from_json,subOption2 = 200
1.5 IConfigureNamedOptions 选项命名
IConfigureNamedOptions: 是用于对选项类在注入服务时, 进行命名. 下面是把 MyOptions 选项类注入到服务, 并取了别名 named_options_1. 如下所示:
- services.Configure<MyOptions>("named_options_1", Configuration);
- // 在要使用的页面, 如下所示:
- private readonly MyOptions _named_options_1;
- public IndexModel(
- IOptionsSnapshot<MyOptions> namedOptionsAccessor)
- {
- _named_options_1 = namedOptionsAccessor.Get("named_options_1");
- }
- // IOptionsSnapshot 源码
- public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
- {
- //
- // 摘要:
- // Returns a configured TOptions instance with the given name.
- TOptions Get(string name);
- }
- 1.6 ConfigureAll
上面介绍的选项类, 在注入服务时都是使用的 services.Configure, 它是针对选项类的当前实例, 例如: 在 page1 和 page2 都使用了实例 MyOptions( private readonly MyOptions _options) 但它们属于不同的实例.
- // 使用 ConfigureAll 方法配置所有选项实例
- services.ConfigureAll<MyOptions>(myOptions =>
- {
- // 所有 MyOptions 实例配置 Option1 的值
- myOptions.Option1 = "ConfigureAll replacement value";
- });
- // 添加代码后运行示例应用将产生以下结果:
- named_options_1: option1 = ConfigureAll replacement value, option2 = -1
- named_options_2: option1 = ConfigureAll replacement value, option2 = 5
总结:
选项模式是对 Configuration 配置的功能扩展, 主要用于把 JSON 文件序列化到. net 类 (选项类). 通过注入 services. Configure 或 services.ConfigureAll 把选项类注入到服务并绑定到 Configuration 上. 选项这篇还有其它功能如: 选项后期配置 ( IPostConfigureOptions), 启动期间访问选项, 选项验证等, 详细了解查看官网
参考文献
官方资料: ASP.NET core 选项
来源: https://www.cnblogs.com/MrHSR/p/10291766.html