1.前言

选项(Options)模式是对配置(Configuration)的功能的延伸。在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类、绑定至对象图、将数组绑定至类)而选项模式又有个选项类(TOptions),该选项类作用是指:把选项类中的属性与配置来源中的键关联起来。举个例,假设json文件有个Option1键,选项类中也有个叫Option1的属性名,经过选项配置,这样就能把json中的键的值映射到选项类属性值中。也可以理解在项目应用中,把一个json文件序列化到.net类。

2.常规选项配置

选项类必须为包含公共无参数构造函数的非抽象类。在appsettings.json文件中添加option1、option2、subsection的配置:

  1. {
  2. "option1": "value1_from_json",
  3. "option2": -,
  4. "subsection": {
  5. "suboption1": "subvalue1_from_json",
  6. "suboption2":
  7. },
  8. "Logging": {
  9. "LogLevel": {
  10. "Default": "Warning"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }

新建MyOptions类(Models/MyOptions.cs),以下类MyOptions具有三种属性:Option1和 Option2。设置默认值为可选,但以下示例中的类构造函数设置了Option1的默认值。Option2具有通过直接初始化属性设置的默认值:

  1. public class MyOptions
  2. {
  3. public MyOptions()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = ;
  10. }

而MyOptions类通过Configure添加到服务容器并绑定到配置:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Example #1: General configuration
  4. // Register the Configuration instance which MyOptions binds against.
  5. services.Configure<MyOptions>(Configuration);
  6. }

也可以使用自定义ConfigurationBuilder从设置文件加载选项配置时,确认基路径设置正确,添加到服务容器并绑定到配置:

  1. var configBuilder = new ConfigurationBuilder()
  2. .SetBasePath(Directory.GetCurrentDirectory())
  3. .AddJsonFile("appsettings.json", optional: true);
  4. var config = configBuilder.Build();
  5. services.Configure<MyOptions>(config);

以下页面模型通过IOptionsMonitor<TOptions>使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs):

  1. public class IndexModel
  2. {
  3. public IndexModel(IOptionsMonitor<MyOptions> optionsAccessor)
  4. {
  5. _options = optionsAccessor.CurrentValue;
  6. }
  7. private readonly MyOptions _options;
  8. public void OnGet()
  9. {
  10. // Example #1: Simple options
  11. var option1 = _options.Option1;
  12. var option2 = _options.Option2;
  13. var simpleOptions = $"option1 = {option1}, option2 = {option2}";
  14. }
  15. }

在Home/Index控制器Action下调用IndexModel.OnGet方法返回包含选项值的字符串:

  1. public HomeController(IOptionsMonitor<MyOptions> optionsAccessor)
  2. {
  3. _optionsAccessor = optionsAccessor;
  4. }
  5. private readonly IOptionsMonitor<MyOptions> _optionsAccessor;
  6. public IActionResult Index()
  7. {
  8. IndexModel indexModel = new IndexModel(_optionsAccessor);
  9. indexModel.OnGet();
  10. return View();
  11. }

3.通过委托配置简单选项

使用委托设置选项值。此示例应用程序使用新建MyOptionsWithDelegateConfig类 (Models/MyOptionsWithDelegateConfig.cs):

  1. public class MyOptionsWithDelegateConfig
  2. {
  3. public MyOptionsWithDelegateConfig()
  4. {
  5. // Set default value.
  6. Option1 = "value1_from_ctor";
  7. }
  8. public string Option1 { get; set; }
  9. public int Option2 { get; set; } = ;
  10. }

向服务容器添加IConfigureOptions<TOptions>服务。它通过MyOptionsWithDelegateConfig使用委托来配置绑定:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Example #2: Options bound and configured by a delegate
  4. services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
  5. {
  6. myOptions.Option1 = "value1_configured_by_delegate";
  7. myOptions.Option2 = ;
  8. });
  9. }

以下页面模型通过IOptionsMonitor<TOptions>使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs):

  1. public class IndexModel
  2. {
  3. private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
  4. public IndexModel(IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig)
  5. {
  6. _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
  7. }
  8. public void OnGet()
  9. {
  10. // Example #2: Options configured by delegate
  11. var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
  12. var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
  13. var simpleOptionsWithDelegateConfig =
  14. $"delegate_option1 = {delegate_config_option1}, " +
  15. $"delegate_option2 = {delegate_config_option2}";
  16. }
  17. }

在Home/Index控制器Action下调用IndexModel.OnGet方法返回包含选项值的字符串:

  1. public HomeController(IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig)
  2. {
  3. _optionsAccessorWithDelegateConfig = optionsAccessorWithDelegateConfig;
  4. }
  5. private readonly IOptionsMonitor<MyOptionsWithDelegateConfig> _optionsAccessorWithDelegateConfig;
  6. public IActionResult Index()
  7. {
  8. IndexModel indexModel = new IndexModel(_optionsAccessorWithDelegateConfig);
  9. indexModel.OnGet();
  10. return View();
  11. }


每次调用Configure都会将IConfigureOptions<TOptions>服务添加到服务容器。在前面的示例中,Option1和Option2的值同时在appsettings.json中指定,但Option1和Option2的值被配置的委托替代。当启用多个配置服务时,指定的最后一个配置源优于其他源,由其设置配置值。运行应用程序时,页面模型的OnGet方法返回显示选项类值的字符串。

4.子选项配置

将选项绑定到配置时,选项类型中的每个属性都将绑定到窗体property[:sub-property:]的配置键。例如,MyOptions.Option1属性将绑定到从appsettings.json中的option1属性读取的键Option1。在以下代码中,已向服务容器添加IConfigureOptions<TOptions>服务。它将MySubOptions绑定到appsettings.json文件的subsection部分:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Example #3: Suboptions
  4. // Bind options using a sub-section of the appsettings.json file.
  5. services.Configure<MySubOptions>(Configuration.GetSection("subsection"));
  6. }

新建MySubOptions类(Models/MySubOptions.cs)将属性SubOption1和SubOption2定义为保留选项值:

  1. public class MySubOptions
  2. {
  3. public MySubOptions()
  4. {
  5. // Set default values.
  6. SubOption1 = "value1_from_ctor";
  7. SubOption2 = ;
  8. }
  9. public string SubOption1 { get; set; }
  10. public int SubOption2 { get; set; }
  11. }

以下页面模型通过IOptionsMonitor<TOptions>使用构造函数依赖关系注入来访问设置(Pages/Index.cshtml.cs):

  1. public class IndexModel
  2. {
  3. private readonly MySubOptions _subOptions;
  4. public IndexModel(IOptionsMonitor<MySubOptions> subOptionsAccessor)
  5. {
  6. _subOptions = subOptionsAccessor.CurrentValue;
  7. }
  8. public void OnGet()
  9. {
  10. // Example #3: Suboptions
  11. var subOption1 = _subOptions.SubOption1;
  12. var subOption2 = _subOptions.SubOption2;
  13. var subOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";
  14. }
  15. }

在Home/Index控制器Action下调用IndexModel.OnGet方法返回包含选项值的字符串:

  1. public HomeController(IOptionsMonitor<MySubOptions> subOptionsAccessor)
  2. {
  3. _subOptionsAccessor = subOptionsAccessor;
  4. }
  5. private readonly IOptionsMonitor<MySubOptions> _subOptionsAccessor;
  6. public IActionResult Index()
  7. {
  8. IndexModel indexModel = new IndexModel(_subOptionsAccessor);
  9. indexModel.OnGet();
  10. return View();
  11. }

5.通过IOptionsSnapshot重新加载配置数据

IOptionsSnapshot针对请求生命周期访问和缓存选项时,每个请求只能计算一次选项。以下示例演示如何在更改appsettings.json(Pages/Index.cshtml.cs)后创建新的 IOptionsSnapshot<TOptions>。在更改appsettings.json文件和重新加载配置之前,针对服务器的多个请求返回appsettings.json文件提供的配置键值。

  1. public class IndexModel
  2. {
  3. private readonly MyOptions _snapshotOptions;
  4. public IndexModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
  5. {
  6. _snapshotOptions = snapshotOptionsAccessor.Value;
  7. }
  8. public void OnGet()
  9. {
  10. // Example #5: Snapshot options
  11. var snapshotOption1 = _snapshotOptions.Option1;
  12. var snapshotOption2 = _snapshotOptions.Option2;
  13. var snapshotOptions = $"snapshot option1 = {snapshotOption1}, " + $"snapshot option2 = {snapshotOption2}";
  14. }
  15. }

下面显示从appsettings.json文件加载的初始option1和option2值:

  1. snapshot option1 = value1_from_json, snapshot option2 = -

将appsettings.json文件中的值更改为value1_from_json UPDATED和200。保存appsettings.json 文件。刷新浏览器,查看更新的选项值:

  1. snapshot option1 = value1_from_json UPDATED, snapshot option2 =

6.包含IConfigureNamedOptions的命名选项支持

命名选项支持允许应用程序在命名选项配置之间进行区分。命名选项通过OptionsServiceCollectionExtensions.Configure进行声明,其调用扩展方法ConfigureNamedOptions<TOptions>.Configure:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Example #6: Named options (named_options_1)
  4. // Register the ConfigurationBuilder instance which MyOptions binds against.
  5. // Specify that the options loaded from configuration are named
  6. // "named_options_1".
  7. services.Configure<MyOptions>("named_options_1", Configuration);
  8.  
  9. // Example #6: Named options (named_options_2)
  10. // Specify that the options loaded from the MyOptions class are named
  11. // "named_options_2".
  12. // Use a delegate to configure option values.
  13. services.Configure<MyOptions>("named_options_2", myOptions =>
  14. {
  15. myOptions.Option1 = "named_options_2_value1_from_action";
  16. });
  17. }

通过OnGet(Pages/Index.cshtml.cs)访问命名选项:

  1. public class IndexModel
  2. {
  3. private readonly MyOptions _named_options_1;
  4. private readonly MyOptions _named_options_2;
  5. public IndexModel(IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  6. {
  7. _named_options_1 = namedOptionsAccessor.Get("named_options_1");
  8. _named_options_2 = namedOptionsAccessor.Get("named_options_2");
  9. }
  10. public void OnGet()
  11. {
  12. // Example #6: Named options
  13. var named_options_1 =
  14. $"named_options_1: option1 = {_named_options_1.Option1}, " +
  15. $"option2 = {_named_options_1.Option2}";
  16. var named_options_2 =
  17. $"named_options_2: option1 = {_named_options_2.Option1}, " +
  18. $"option2 = {_named_options_2.Option2}";
  19. var namedOptions = $"{named_options_1} {named_options_2}";
  20. }
  21. }

在Home/Index控制器Action下调用IndexModel.OnGet方法返回包含选项值的字符串:

  1. public HomeController(IOptionsSnapshot<MyOptions> namedOptionsAccessor)
  2. {
  3. _namedOptionsAccessor = namedOptionsAccessor;
  4. }
  5. private readonly IOptionsSnapshot<MyOptions> _namedOptionsAccessor;
  6. public IActionResult Index()
  7. {
  8. IndexModel indexModel = new IndexModel(_namedOptionsAccessor);
  9. indexModel.OnGet();
  10. return View();
  11. }

5.1使用ConfigureAll方法配置所有选项

使用ConfigureAll方法可以配置所有选项实例。以下代码将针对包含公共值的所有配置实例配置Option1。将以下代码手动添加到Startup.ConfigureServices方法:

  1. services.ConfigureAll<MyOptions>(myOptions =>
  2. {
  3. myOptions.Option1 = "ConfigureAll replacement value";
  4. });

在Home/Index控制器Action下调用IndexModel.OnGet方法返回包含选项值的字符串:

参考文献:
ASP.NET Core 中的选项模式

(13)ASP.NET Core 中的选项模式(Options)的更多相关文章

  1. asp.net core 3.0 选项模式1:使用

    本篇只是从应用角度来说明asp.net core的选项模式,下一篇会从源码来分析 1.以前的方式 以前我们使用web.config/app.config时是这样使用配置的 var count = Co ...

  2. ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项

    前言 还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧.在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注 ...

  3. C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入

    C# 嵌入dll   在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...

  4. ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态

    原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...

  5. 避免在ASP.NET Core中使用服务定位器模式

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:服务定位器(Service Locator)作为一种反模式,一般情况下应该避免使用,在 ...

  6. [译]ASP.NET Core中使用MediatR实现命令和中介者模式

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何 ...

  7. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  8. Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式

    一.前言 上一篇我分享了一篇关于 Asp.Net Core 中IdentityServer4 授权中心之应用实战 的文章,其中有不少博友给我提了问题,其中有一个博友问我的一个场景,我给他解答的还不够完 ...

  9. Asp.Net Core中服务的生命周期选项区别和用法

    在做一个小的Demo中,在一个界面上两次调用视图组件,并且在视图组件中都调用了数据库查询,结果发现,一直报错,将两个视图组件的调用分离,单独进行,却又是正常的,寻找一番,发现是配置依赖注入服务时,对于 ...

随机推荐

  1. Docker安装nacos1.0.0固定ip单机模式

    1 从dockerHub拉取镜像到本地 docker pull nacos/nacos-server:1.0.0 2 创建目录(宿主机) 2.1 日志目录 mkdir -p /docker/nacos ...

  2. 用ASP.NET Core重写了一款网络考试培训的免费软件

    在IT圈混迹了近十年,今已正当而立之年却仍一事无成,心中倍感惶恐惭愧.面对竟争如此激列的环境,该如何应对?却也知不能让自已闲着,得转起来,动起来.于是,便想着利用最新技术栈将自已原来的收费产品重写一次 ...

  3. Go - Map 集合

    目录 概述 声明 Map 生成 JSON 编辑和删除 推荐阅读 概述 Map 集合是无序的 key-value 数据结构. Map 集合中的 key / value 可以是任意类型,但所有的 key ...

  4. 一张图带你了解webpack的require.context

    很多人应该像我一样,对于webpack的require.context都是一知半解吧.网上很多关于require.context的使用案例,但是我没找到可以帮助我理解这个知识点的,于是也决定自己来探索 ...

  5. XML中如果有特殊字符,比如> < 解决方案

    //只需要在代码前加这个就可以了<![CDATA[ 把代码写到这个位置 ]]>

  6. redis 发布和订阅实现

    参考文献 15天玩转redis -- 第九篇 发布/订阅模式 <Redis设计与实现> 命令简介 在redis用户手册中,跟发布订阅相关的命令有如下的六个: PSUBSCRIBE PUBL ...

  7. django基础知识之HttpReqeust对象:

    HttpReqeust对象 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象 视图函数的第一个参数是HttpRequest对象 在django.http模块中定义了HttpR ...

  8. VS2013日常使用若干技巧+快捷键

    1.注释的方法 1)sqlserver中,单行注释:— —   多行注释:/* 代码  */ 2)C#中,单行注释://    多行注释:/* 代码  */ 3)C#中多行注释的快捷方式:先选中你要注 ...

  9. 开源FTP/SFTP客户端 FileZilla v3.31.0 绿色便携版

    下载地址:点我 基本介绍 FileZilla是一种快速.可信赖的FTP客户端以及服务器端开放源代码程式,具有多种特色.直觉的接口.可控性.有条理的界面和管理多站点的简化方式使得Filezilla客户端 ...

  10. 解决webpack打包速度慢的解决办法

    技巧1 webpack在打包的时候第一次总是会做很长的准备工作,包括加载插件之类的.在刚接触webpack的时候总是webpack一下-测一下-改一下-再webpack一下,这种方式最后让很多人崩溃了 ...