一.概述

  本章讲的选项模式是对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; }
}

    (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; } = ;
  }
       //将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": -,

    当配置文件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; } = ;
    }
         services.Configure<MyOptions>(Configuration);
//第二个注入服务
services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
{
         // 在Page1Model构造方法中生成MyOptionsWithDelegateConfig实例时调用
myOptions.Option1 = "value1_configured_by_delegate";
myOptions.Option2 = ;
});

    

    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 = -,option2 =
    // MyOptionsWithDelegateConfig实例取值如下:
    delegate_option1 = value1_configured_by_delegate,delegate_option2 =

  1.4 子选项配置

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

      "Option1": "value1_from_json",
    "Option2": -,
    "subsection": {
     "suboption1": "subvalue1_from_json",
    "suboption2":
    }
     public class MySubOptions
   {
   public MySubOptions()
  {
   // Set default values.
   SubOption1 = "value1_from_ctor";
   SubOption2 = ;
   }    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 =

    

  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 = -
  named_options_2: option1 = ConfigureAll replacement value, option2 =

 

  总结:

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

参考文献

官方资料:asp.net core 选项

asp.net core 系列 12 选项 TOptions的更多相关文章

  1. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  2. (13)ASP.NET Core 中的选项模式(Options)

    1.前言 选项(Options)模式是对配置(Configuration)的功能的延伸.在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类.绑定至对 ...

  3. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  4. asp.net core系列 40 Web 应用MVC 介绍与详细示例

    一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...

  5. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  6. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  7. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

  8. asp.net core 系列 18 web服务器实现

    一. ASP.NET Core Module 在介绍ASP.NET Core Web实现之前,先来了解下ASP.NET Core Module.该模块是插入 IIS 管道的本机 IIS 模块(本机是指 ...

  9. asp.net core 系列 17 通用主机 IHostBuilder

    一.概述 ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用.通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从 ...

随机推荐

  1. 《Spark大数据处理》---Spark原理

  2. Date动态获取时间

    ·getDate            |  根据本地时间获取当前日期(本月的几号) ·getDay             |  根据本地时间获取今天是星期几(0-Sunday,1-Monday.. ...

  3. 小白的学习之路(hello wold!)

    Hello word ! 一直想写博客,但是都拖延了,正好两天有假期就开始弄这个事情了.开始觉得写博客也没有什么,一路学习以来都是看别人的博客进行学习,也收藏了不少博客,学到了不少东西,所以我觉的博客 ...

  4. Response输出excel设置文本样式

    在网上查了些Response导出excel然后设置样式的方法,发现没有一个可行的于是开始自己研究, 发现可以通过输出样式的方式进行配置,我要设置的是全文本格式在excel样式是这样的mso-numbe ...

  5. Hadoop namenode节点无法启动的问题解决

    namenode是Hadoop集群HDFS的管理节点,管理着整个分布式文件系统的命名空间,以及文件与块的映射关系等,在Hadoop集群中扮演着至关重要的作用. 我之前安装的Hadoop集群中namen ...

  6. KMP模板实现

    看了出题知识点才发现自己连KMP都没有好好的理解,甚至一共就打过一次板子=-= 于是照着之前的课件学了一学...发现没怎么弄懂qwq 我太弱啦! 找了一篇自认为全网最好的介绍 觉得写得很棒 字符串匹配 ...

  7. PHP通过经纬坐标计算两个地址的距离

    <?php /** *求两个已知经纬度之间的距离,单位为米 * *@param lng1,lng2 经度 * *@param lat1,lat2 纬度 * *@return float 距离,单 ...

  8. git 实际操作

    1.把文件添加到版本库中. 所有的版本控制系统只能跟踪文本文件的改动 下面先看下demo如下演示: 我在版本库gittest目录下新建一个记事本文件 1.txt 内容如下:1111111 第一步:使用 ...

  9. 马昕璐 201771010118《面向对象程序设计(java)》第十八周学习总结

    实验十八  总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设 ...

  10. Recycle移动端界面设计成果图

    经过功能分析,我最终设计出来了该App界面图: (1)主页面图 (2)消息界面图 (3)我的界面图 (4)垃圾页面图 由于时间原因,此次设计仅为初稿.以后会继续抽出时间,与团队成员一起完善该项目App ...