asp.net core 系列 12 选项 TOptions
一.概述
本章讲的选项模式是对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; } = 5; }
//将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": -1,
当配置文件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; } = 5; }
services.configure<myoptions>(configuration); //第二个注入服务 services.configure<myoptionswithdelegateconfig>(myoptions => {
// 在page1model构造方法中生成myoptionswithdelegateconfig实例时调用 myoptions.option1 = "value1_configured_by_delegate"; myoptions.option2 = 500; });
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 = -1,option2 = 5 // myoptionswithdelegateconfig实例取值如下: delegate_option1 = value1_configured_by_delegate,delegate_option2 = 500
1.4 子选项配置
当配置文件中的子节点需要与选项类进行关联映射时,可以通过服务注入bind到指定的configuration节点。在以下代码中,已向服务容器添加第三个 iconfigureoptions<toptions> 服务。 它将 mysuboptions 绑定到 appsettings.json 文件的 subsection 部分:
"option1": "value1_from_json", "option2": -1, "subsection": { "suboption1": "subvalue1_from_json", "suboption2": 200 }
public class mysuboptions { public mysuboptions() { // set default values. suboption1 = "value1_from_ctor"; suboption2 = 5; } 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 = 200
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 = -1 named_options_2: option1 = configureall replacement value, option2 = 5
总结:
选项模式是对configuration配置的功能扩展,主要用于把json文件序列化到.net类(选项类)。通过注入services. configure或services.configureall把选项类注入到服务并绑定到configuration上。 选项这篇还有其它功能如:选项后期配置( ipostconfigureoptions), 启动期间访问选项, 选项验证等,详细了解查看官网
参考文献
官方资料:
上一篇: 和女朋友一起做饭好开心,就不怕炸了吗?!
下一篇: 哟,搭顺风车呢?
推荐阅读
-
asp.net core系列 24 EF模型配置(主键,生成值,最大长度,并发标记)
-
ASP.NET Core 2.2 WebApi 系列【六】泛型仓储模式
-
ASP.NET Core 2.2 WebApi 系列【三】AutoFac 仓储接口的依赖注入
-
ASP.NET Core 2.2 WebApi 系列【四】集成Swagger
-
asp.net core系列 66 Dapper介绍--Micro-ORM
-
asp.net core系列 68 Filter管道过滤器
-
ASP.NET Core 选项模式源码学习Options IOptions(二)
-
Asp.Net Core2.2 源码阅读系列——控制台日志源码解析
-
ASP.NET Core 2.2 系列【三】集成Swagger
-
asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用