一.概述

  本章讲的选项模式是对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. redis的雪崩与穿透原理的浅理解

    首先列一下主要说什么, 1.什么是Redis缓存的雪崩? 2.什么是Redis缓存的穿透? 3.Redis缓存崩溃会怎么样? 4.怎么预防Redis缓存崩溃? 1.什么是Redis缓存的雪崩? 举个栗 ...

  2. jmeter主要函数助手功用说明

    jmeter中虽然有很多的插件,但是有些需要安装,有些具有一定的局限性.函数助手是一个快捷的工具库.下面记录一下函数助手中一些主要的函数的使用方法. 注:不内容中所有的实例均基于3.2记录 1._Be ...

  3. python基础----1. globals和locals

    官方文档 globals """ Return a dictionary representing the current global symbol table. Th ...

  4. 网络编程-SOCKET开发之----2. TCP粘包现象产生分析

    1. 粘包现象及产生原因 1)概念 指TCP协议中,发送方发送的若干个包数据到接收方接收时粘成一包.发送方粘包:发送方把若干个要发送的数据包封装成一个包,一次性发送,减少网络IO延迟:接收方粘包:接收 ...

  5. django -使用jinja2模板引擎 自定义的过滤器

    setting.py中 TEMPLATES = [ { 'BACKEND': 'django.template.backends.jinja2.Jinja2', 'DIRS': [os.path.jo ...

  6. h5软键盘挡住输入框问题解决(android)

    问题 移动端浏览器中的表单在部分android机型上测试,点击靠下的输入框时会遇到弹出的软键盘挡住输入框问题 ios可自身弹起(ios自身的调整偶尔也会出问题,例如第三方键盘会遮挡,原因是第三方输入法 ...

  7. Web开发者の实用代码账簿

    介里就都是恶魔菌整理的我平时会用的代码啦-现在在这里总结规划一下,希望能对你以及其他阅读这篇文章的小可耐们有帮助喵!欢迎订阅我的博客来get恶魔菌记事簿的新动态鸭! ↓ ↓ ↓ 以下就是内容啦~记得看 ...

  8. 常见的UI框架

    移动端框架 1.Admui 管理系统快速开发框架--http://docs.admui.com/ 为什么选择Admui?代码开源--开放所有源码,不存在任何加密混淆代码,安全全程可控,开箱即用--包含 ...

  9. CSS-默认padding 和 margin

    一.h1~h6标签:有默认margin(top,bottom且相同)值,没有默认padding值. 在chrome中:16,15,14,16,17,19; 在firefox中:16,15,14,16, ...

  10. 课堂作业Complex类的实现

    #include <iostream> #include <cmath> using namespace std; class Complex{ public: Complex ...