本章讲的选项模式是对Configuration配置的功能扩展。 讲这篇时有个专用名词叫“选项类(TOptions)” 。该选项类作用是指:把选项类中的属性与配置来源中的键关联起来。举个例,假设json文件有个Option1键,选项类中也有个叫Option1的属性名,经过选项配置,这样就能把json中的键的值映射到选项类属性值中。也可以理解在项目应用中,把一个json文件序列化到.net类。

 

  1.1选项接口介绍

    在官方文档中选项接口有很多,这里列举了这些选项接口。所有选项接口基本都继承了TOptions接口。

  1. // Used for notifications when TOptions instances change
  2. public interface IOptionsMonitor<out TOptions>
  3. {
  4. //
  5. // 摘要:
  6. // Returns the current TOptions instance with the Microsoft.Extensions.Options.Options.DefaultName.
  7. TOptions CurrentValue { get; }
  8. //...
  9. }
  10. // Used to create TOptions instances
  11. public interface IOptionsFactory<TOptions> where TOptions : class, new()
  12. {
  13. //
  14. // 摘要:
  15. // Returns a configured TOptions instance with the given name.
  16. TOptions Create(string name);
  17. }
  18. // Represents something that configures the TOptions type. Note: These are run before all
  19. public interface IConfigureOptions<in TOptions> where TOptions : class
  20. {
  21. //
  22. // 摘要:
  23. // Invoked to configure a TOptions instance.
  24. //
  25. // 参数:
  26. // options:
  27. // The options instance to configure.
  28. void Configure(TOptions options);
  29. }
  30. public interface IPostConfigureOptions<in TOptions> where TOptions : class
  31. {
  32. //
  33. // 摘要:
  34. // Invoked to configure a TOptions instance.
  35. //
  36. // 参数:
  37. // name:
  38. // The name of the options instance being configured.
  39. //
  40. // options:
  41. // The options instance to configured.
  42. void PostConfigure(string name, TOptions options);
  43. }
  44. public interface IConfigureNamedOptions<in TOptions> : IConfigureOptions<TOptions> where TOptions : class
  45. {
  46. //
  47. // 摘要:
  48. // Invoked to configure a TOptions instance.
  49. //
  50. // 参数:
  51. // name:
  52. // The name of the options instance being configured.
  53. //
  54. // options:
  55. // The options instance to configure.
  56. void Configure(string name, TOptions options);
  57. }
  58. // Used by IOptionsMonitor<TOptions> to cache TOptions instances.
  59. public interface IOptionsMonitorCache<TOptions> where TOptions : class
  60. {
  61. //
  62. // 摘要:
  63. // Clears all options instances from the cache.
  64. void Clear();
  65. //
  66. // 摘要:
  67. // Gets a named options instance, or adds a new instance created with createOptions.
  68. //
  69. // 参数:
  70. // name:
  71. // The name of the options instance.
  72. //
  73. // createOptions:
  74. // The func used to create the new instance.
  75. //
  76. // 返回结果:
  77. // The options instance.
  78. TOptions GetOrAdd(string name, Func<TOptions> createOptions);
  79. //
  80. // 摘要:
  81. // Tries to adds a new option to the cache, will return false if the name already
  82. // exists.
  83. //
  84. // 参数:
  85. // name:
  86. // The name of the options instance.
  87. //
  88. // options:
  89. // The options instance.
  90. //
  91. // 返回结果:
  92. // Whether anything was added.
  93. bool TryAdd(string name, TOptions options);
  94. //
  95. // 摘要:
  96. // Try to remove an options instance.
  97. //
  98. // 参数:
  99. // name:
  100. // The name of the options instance.
  101. //
  102. // 返回结果:
  103. // Whether anything was removed.
  104. bool TryRemove(string name);
  105. }
  106. // Used to access the value of TOptions for the lifetime of a request
  107. public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
  108. {
  109. //
  110. // 摘要:
  111. // Returns a configured TOptions instance with the given name.
  112. TOptions Get(string name);
  113. }
  114. //Used to retrieve configured TOptions instances
  115. public interface IOptions<out TOptions> where TOptions : class, new()
  116. {
  117. //
  118. // 摘要:
  119. // The default configured TOptions instance
  120. TOptions Value { get; }
  121. }

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 具有通过直接初始化属性设置的默认值。

  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.   }
  1. //将MyOptions类已通过Configure添加到服务容器,并绑定到配置IConfiguration上
  2. //Registers a configuration instance which TOptions will bind against.
  3. services.Configure<MyOptions>(Configuration);
  1. private readonly MyOptions _options;
         //OtherPages/Page1
  2. public Page1Model( IOptionsMonitor<MyOptions> optionsAccessor)
  3. {
  4. _options = optionsAccessor.CurrentValue;
  5. }
  6. public void OnGet() {
  7. var option1 = _options.Option1;
  8. var option2 = _options.Option2;
  9. var SimpleOptions = $"option1 = {option1}, option2 = {option2}";
  1.     // 此时SimpleOptions值:"option1 = value1_from_ctor, option2 = 5"
  1.   //下面在appsettings.json 文件添加 option1 和 option2 的值。
  2.   "option1": "value1_from_json",
  3.   "option2": -1,

    当配置文件appsettings.json中option1和option2键的值改变后,MyOptions 选项类中的属性option1和option2的值也会改变。 下面再次运行OtherPages/Page1

  1.       //此时SimpleOptions的值为:"option1 = value1_from_json, option2 = -1"

    为什么MyOptions类中option1,option2会取到appsettings.json文件中的值呢?因为MyOptions选项类注入到Iconfiguration服务后与appsettings.json文件中键相同,形成了映射。

 

  1.3 通过委托配置简单选项

     使用委托设置选项值。 此示例应用使用 MyOptionsWithDelegateConfig 类 ,这里仍然是使用相同的键Option1,Option2。 它通过 MyOptionsWithDelegateConfig 使用委托来配置绑定。

  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.     }
  1. services.Configure<MyOptions>(Configuration);
  2. //第二个注入服务
  3. services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
  4. {
             // 在Page1Model构造方法中生成MyOptionsWithDelegateConfig实例时调用
  5. myOptions.Option1 = "value1_configured_by_delegate";
  6. myOptions.Option2 = 500;
  7. });

    

  1.     public Page1Model(
  2. IConfiguration configuration,
  3. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  4. IOptionsMonitor<MyOptions> optionsAccessor
  5. )
  6. {
  7. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  8. _options = optionsAccessor.CurrentValue;
  9. Configuration = configuration;
  10. }
  11. public IConfiguration Configuration { get; }
  12. private readonly MyOptions _options;
  13. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  14. public string BindGUIDMsg { get; set; }
  15. public void OnGet()
  16. {
  17. BindGUIDMsg = $"option1 = {_options.Option1}, option2 = {_options.Option2}";
  18. BindGUIDMsg += "</br>";
  19. BindGUIDMsg += $"delegate_option1 = {_optionsWithDelegateConfig.Option1}, " +
  20. $"delegate_option2 = {_optionsWithDelegateConfig.Option2}";
  21. }

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

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

  1.     // myOptions实例取值如下:
  2.     SimpleOptionsoption1 = -1option2 = 5
  3.     // MyOptionsWithDelegateConfig实例取值如下:
  4.     delegate_option1 = value1_configured_by_delegatedelegate_option2 = 500

 

   1.4 子选项配置

     当配置文件中的子节点需要与选项类进行关联映射时,可以通过服务注入bind到指定的Configuration节点。在以下代码中,已向服务容器添加第三个 IConfigureOptions<TOptions> 服务。 它将 MySubOptions 绑定到 appsettings.json 文件的 subsection 部分:

  1.     "Option1": "value1_from_json",
  2.     "Option2": -1,
  3.     "subsection": {
  4.      "suboption1": "subvalue1_from_json",
  5.     "suboption2": 200
  6.     }
  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.    }
  1. //第三个IConfigureOptions<TOptions>注入服务
  2. services.Configure<MySubOptions>(Configuration.GetSection("subsection"));
  1. //OtherPages/Page1
  2. public Page1Model(
  3. IConfiguration configuration,
  4. IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
  5. IOptionsMonitor<MyOptions> optionsAccessor,
  6. IOptionsMonitor<MySubOptions> subOptionsAccessor
  7. )
  8. {
  9. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  10. _options = optionsAccessor.CurrentValue;
  11. _subOptions = subOptionsAccessor.CurrentValue;
  12. Configuration = configuration;
  13. }
  14. public IConfiguration Configuration { get; }
  15. private readonly MyOptions _options;
  16. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  17. private readonly MySubOptions _subOptions;
  1. // OnGet方法
  2.   SubOptions = $"subOption1 = {_subOptions.SubOption1}, subOption2 = {_subOptions.SubOption2}"
  1.   //运行应用时,OnGet 方法返回显示子选项类值的字符串:
  2.   // MySubOptions实例取值如下:
  3.    subOption1 = subvalue1_from_jsonsubOption2 = 200

    

  1.5 IConfigureNamedOptions选项命名

    IConfigureNamedOptions:是用于对选项类在注入服务时,进行命名。下面是把MyOptions选项类注入到服务,并取了别名named_options_1。 如下所示:

  1.   services.Configure<MyOptions>("named_options_1", Configuration);
  1.     //在要使用的页面,如下所示:
  2.     private readonly MyOptions _named_options_1;
  3.     public IndexModel(
  4.     IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  5.     {
  6.      _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  7.     }
  1.   // IOptionsSnapshot源码
  2.    public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
  3.    {
  4.    //
  5.    // 摘要:
  6.    // Returns a configured TOptions instance with the given name.
  7.    TOptions Get(string name);
  8.    }

 

  1.6 ConfigureAll 

    上面介绍的选项类,在注入服务时都是使用的services.Configure,它是针对选项类的当前实例,例如:在page1和page2都使用了实例MyOptions( private readonly MyOptions _options)但它们属于不同的实例。 

  1.   //使用 ConfigureAll 方法配置所有选项实例
  2. services.ConfigureAll<MyOptions>(myOptions =>
  3. {
  4. //所有MyOptions实例配置 Option1的值
  5. myOptions.Option1 = "ConfigureAll replacement value";
  6. });
  1.   //添加代码后运行示例应用将产生以下结果:
  2.   named_options_1: option1 = ConfigureAll replacement value, option2 = -1
  3.   named_options_2: option1 = ConfigureAll replacement value, option2 = 5

 

  总结:

         选项模式是对Configuration配置的功能扩展,主要用于把json文件序列化到.net类(选项类)。通过注入services. Configure或services.ConfigureAll把选项类注入到服务并绑定到Configuration上。 选项这篇还有其它功能如:选项后期配置( IPostConfigureOptions), 启动期间访问选项, 选项验证等,详细了解查看官网

 

参考文献

官方资料:asp.net core 选项

posted on 2019-01-21 11:47 花阴偷移 阅读() 评论() 编辑 收藏

版权声明:本文为MrHSR原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/MrHSR/p/10291766.html