一.概述

  本章讲的选项模式是对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. Mix 导航

    Mix 导航 一.程序员必备技能 Markdonw 使用 Git 常用命令 二.分析设计 UML 三.其他 博客园代码样式修改

  2. PBRT笔记(12)——蒙特卡洛积分

    这里还涉及到pdf.方差等概念,推荐去看<全局光照技术:从离线到实时渲染> 积累分布函数 cumulative distribution function (CDF) 蒙特卡洛估算 为了计 ...

  3. css实现中文换行,英文换行,超出省略

    英文换行时,是以单词换行,在对应的标签添加对应的属性即可 1 word-break:break-all;只对英文起作用,以字母作为换行依据 2 word-wrap:break-word; 只对英文起作 ...

  4. AWSS3异步等待上传成功返回结果

    /// <summary> /// 流上传文件 /// </summary> /// <param name="data">流内容</pa ...

  5. 图解Raft之日志复制

    日志复制可以说是Raft集群的核心之一,保证了Raft数据的一致性,下面通过几张图片介绍Raft集群中日志复制的逻辑与流程: 在一个Raft集群中只有Leader节点能够接受客户端的请求,由Leade ...

  6. Oracle DBLINK的相关知识整理

    一.DBLINK(Database Link)概念 dblink,顾名思义就是数据库的链接.当我们要跨本地数据库访问另一个数据库中的表的数据时,在本地数据库中就必须要创建远程数据库的dblink,通过 ...

  7. go语言指针理解

  8. ndk编译ffmpeg

    #!/bin/bash NDK=/opt/android-ndk-r9d SYSROOT=$NDK/platforms/android-9/arch-arm/ TOOLCHAIN=$NDK/toolc ...

  9. Linux下CenOS系统 安装Redis

    1.redis下载 进入root目录:cd /root(目录可自定义)   wget http://download.redis.io/releases/redis-3.2.10.tar.gz 红色部 ...

  10. HTML5调用手机摄像机、相册功能 <input>方法

    最近用MUI框架做webapp项目,在有PLUS环境的基础上能直接调用手机底层的API来使用拍照或从相册选择上传功能! 在查资料的时候,想起了另一种用input调用摄像和相册功能的方法,之前没有深入了 ...