一.概述

  本章讲的选项模式是对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. FFT快速傅里叶变换算法

    1.FFT算法概要: FFT(Fast Fourier Transformation)是离散傅氏变换(DFT)的快速算法.即为快速傅氏变换.它是根据离散傅氏变换的奇.偶.虚.实等特性,对离散傅立叶变换 ...

  2. idea使用阿里工具优化代码+阿里开发手册

    idea安装工具 打开插件安装界面 File-Settings-Plugins-Browse repositories... 搜索Alibaba Java Coding Guidelines 进行安装 ...

  3. 在WINDOWS中安装使用SIGPACK(MinGW64+Sublime Text3 &Visual Studio)

    本文介绍在Windows下安装使用SigPack库,涉及Armadillo.OpenBLAS安装使用说明,最终实现对SigPack示例CPP基于MinGW64在Sublime Text3下的编译运行, ...

  4. [OC] 添加 pch 文件

    第一步: Xcode左上角 File - New - File, Other - PCH File 第二步, 在图中位置,写入 pch 的路径. 路径可以将 pch 文件拖入终端来得到.

  5. DCDC设计指南1

    DC/DC电源设计指导:一 在设计电源模块的时候,第一时间要把该电源IC的datasheet资料下载好,查看里面的说明: 下面以一款DC/DC转换IC为例: 开始布局前先看下IC的特性说明,图1: 图 ...

  6. Linux内核内存管理架构

    内存管理子系统可能是linux内核中最为复杂的一个子系统,其支持的功能需求众多,如页面映射.页面分配.页面回收.页面交换.冷热页面.紧急页面.页面碎片管理.页面缓存.页面统计等,而且对性能也有很高的要 ...

  7. mysql命名规范

    1.数据库表命名规范: (1)表名前应该加上前缀,表的前缀一个用系统或模块的英文名称缩写,前缀全部大写或首字母大写,表名中包含的单词首字母大写. (2)数据库表名应该有意义,并且易于理解,最好使用可以 ...

  8. 机器学习(六)K-means聚类、密度聚类、层次聚类、谱聚类

    本文主要简述聚类算法族.聚类算法与前面文章的算法不同,它们属于非监督学习. 1.K-means聚类 记k个簇中心,为\(\mu_{1}\),\(\mu_{2}\),...,\(\mu_{k}\),每个 ...

  9. [LeetCode] Push Dominoes 推多米诺骨牌

    There are N dominoes in a line, and we place each domino vertically upright. In the beginning, we si ...

  10. css基础样式

    1.行间样式:在标签中添加<style>属性      格式:标签名 style="样式:样式值1;样式2=样式值2"   2.内嵌样式:在<head>&l ...