ASP.NET Core - 选项系统之选项使用
上一篇 ASP.NET Core - 选项系统之选项配置 中提到 IOptions、IOptionsMonitor 和 IOptionsSnapshot 三个接口,通过这三个接口都可以从依赖注入容器中解析出已经配置的选项类,在我们通过 Configure 方法配置选项时,这三个接口会被同时注册,但三个接口是有区别的,适用场景也有所不同。
1. IOptions
- IOptions 对象的生命周期是 Singleton (单例),它可以在任意地方进行注入使用
- 该接口对象在第一次使用的时候被实例化,并且选项类中的内容会一直保持不变,前面也提过选项类内容可以在配置来源修改之后更新,但是通过 IOption 解析的选项类不会随着更新而改变
- IOptions 接口不支持命名选项模式,它是没有 get 方法的,也并不会默认读取第一个,它只能读取 String.Empty 默认命名的选项,如果没有配置默认选项的话,虽然也能解析出 Options 选项类对象,但是对象的属性都是相应类型的默认值(引用类型是 null,值类型是 0,其他的也都是相应类型的默认值)
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptions<BlogOptions> options)
{
// 通过 IOptions<TOptions> 接口的 Value 属性读取选项类
// 选项类始终是程序启动时加载的值,不会改变
_blogOptions = options.Value;
}
}
2. IOptionsMonitor
- IOptionsMonitor 对象的生命周期是 Scoped(作用域),Scoped 生命周期的特点是不能注入到 Singleton 服务中
- 在作用域中(最常见的一次Http请求),创建 IOptionsSnapshot 对象实例时,会从配置中读取最新选项值作为快照,并在当前作用域中始终使用该快照。也就是说一次请求中选项类内容保持不变,但是不同请求中可能因为配置来源的修改而不同
- IOptionsMonitor 支持命名选项
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptionsSnapshot<BlogOptions> optionsSnapshot)
{
// IOptionsSnapshot<TOptions> 可以通过 Value 属性读取默认的命名的选项类, Options 对象实例创建时读取的配置快照
_blogOptions = optionsSnapshot.Value;
// 也可以通过 Get 方法获取某一个命名选项,没有指定命名时,默认命名为 string.Empty
//_blogOptions = optionsSnapshot.Get(string.Empty);
}
}
3. IOptionsSnapshot
- IOptionsSnapshot 对象的生命周期也是 Singleton (单例)
- 通过 IOptionsSnapshot 接口注入的对象每次读取选项值时,都是从配置中读取最新选项值,能够实时获取配置来源的更改
- 该接口支持命名选项模式
- 除了可以查看 TOptions 的值,还可以监控 TOptions 配置的更改,支持重新加载配置(CurrentValue),并当配置发生更改时,进行通知(OnChange),支持缓存与缓存失效 (IOptionsMonitorCache),每次调用实例的 CurrentValue 时,会先检查缓存(IOptionsMonitorCache)是否有值,如果有值,则直接用,如果没有,则从配置中读取最新选项值,并记入缓存。当配置发生更改时,会将缓存清空。
public class OptionController : ControllerBase
{
private readonly BlogOptions _blogOptions;
public OptionController(IOptionsMonitor<BlogOptions> optionsMonitor)
{
// IOptionsMonitor<TOptions> 接口没有 Value 属性,通过 CurrentValue 获取选项类对象,
// 每次调用 CurrentValue都会实时读取配置源,始终是最新配置的值
_blogOptions = optionsMonitor.CurrentValue;
// 该接口也支持通过 Get 方法获取命名选项
_blogOptions = optionsMonitor.Get(string.Empty);
// 可以通过 OnChange 注册事件,当配置被加载时会触发事件
optionsMonitor.OnChange(OnOptionsChange);
}
[HttpGet]
public Task<BlogOptions> Get()
{
return Task.FromResult(_blogOptions);
}
private void OnOptionsChange(BlogOptions options)
{
Console.WriteLine(JsonSerializer.Serialize(options));
}
}
启动应用,调用一次 Get 接口,在 Api 控制器构造函数中注册了配置加载触发事件,之后修改 appsettings.json 配置文件中选项类对于的配置节点内容,可以看到事件触发,控制台中输出了改变之后的选项类内容。

4. 三个接口的选项读取机制演示
三个接口解析的选项类的差别,可以通过以下测试清楚得看出:
配置文件中初始选项节点如下:
"Blog": {
"Title": "ASP.NET Core Options11",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
这里为了方便看出 Scoped 生命周期 IOptionSnapeshoot 接口的变化,所有通过 Web Api 接口来测试
public class OptionController : ControllerBase
{
private readonly IOptions<BlogOptions> _blogOptions;
private readonly IOptionsSnapshot<BlogOptions> _blogSnapshotOptions;
private readonly IOptionsMonitor<BlogOptions> _blogMonitorOptions;
public OptionController(
IOptions<BlogOptions> options,
IOptionsSnapshot<BlogOptions> optionsSnapshot,
IOptionsMonitor<BlogOptions> optionsMonitor
)
{
// 注意这里不能再把选项类对象先读取出来,否则选项类对象也不会再改变了
_blogOptions = options;
_blogSnapshotOptions = optionsSnapshot;
_blogMonitorOptions = optionsMonitor;
}
[HttpGet]
public Task Get()
{
Console.WriteLine("第一次读取配置:");
Console.WriteLine("IOptions<TOptions>:" + JsonSerializer.Serialize(_blogOptions.Value));
Console.WriteLine("IOptionsSnapshot<TOptions>:" + JsonSerializer.Serialize(_blogSnapshotOptions.Value));
Console.WriteLine("IOptionsMonitor<TOptions>:" + JsonSerializer.Serialize(_blogMonitorOptions.CurrentValue));
Console.WriteLine("请修改配置文件!");
Console.ReadKey();
Console.WriteLine("第二次读取配置:");
Console.WriteLine("IOptions<TOptions>:" + JsonSerializer.Serialize(_blogOptions.Value));
Console.WriteLine("IOptionsSnapshot<TOptions>:" + JsonSerializer.Serialize(_blogSnapshotOptions.Value));
Console.WriteLine("IOptionsMonitor<TOptions>:" + JsonSerializer.Serialize(_blogMonitorOptions.CurrentValue));
return Task.CompletedTask;
}
}
之后启动应用调用 Get 接口,并在过程中将配置文件内容修改为以下:
"Blog": {
"Title": "ASP.NET Core Options222",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
可以看到控制台的输出中,第二次读取配置的时候,IOptionsMonitor 接口读取到的内容已经改变

之后不要关闭应用,再调一次 Get 接口,并在过程中再次修改配置如下:
"Blog": {
"Title": "ASP.NET Core Options333",
"Content": "This is a blog about Options System in ASP.NET Core Framework.",
"CreateTime": "2022-12-06"
}
这一次的 Get 请求的输出结果如下:

可以看到 IOptionsMonitor 接口每次都能获取到配置文件的实时值,IOptionsSnapshot 接口相较于第一次调用 Get 接口的时候已经改变,获取到了之前修改的值,但是之后的修改它又获取不到了,因为它是 Scoped 生命周期,在一次请求内是保持一致的,而 IOptions 接口获取到的选项类对象是一致不变的。
参考文章:
ASP.NET Core 中的选项模式 | Microsoft Learn
选项模式 - .NET | Microsoft Learn
面向 .NET 库创建者的选项模式指南 - .NET | Microsoft Learn
理解ASP.NET Core - 选项(Options)
ASP.NET Core 系列:
目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core - 选项系统之选项配置
ASP.NET Core - 选项系统之选项使用的更多相关文章
- .NET 黑魔法 - asp.net core 日志系统
asp.net core 里如何记录日志呢? 这要从asp.net core的依赖注入说起,在asp.net core里的依赖注入真是无所不在,各种面向切面的接口与事件. 好吧,来点干货. 首先,我们 ...
- asp.net core后台系统登录的快速构建
登录流程图 示例预览 构建步骤 当然,你也可以直接之前前往coding仓库查看源码,要是发现bug记得提醒我啊~ LoginDemo地址 1. 首先你得有一个项目 2. 然后你需要一个登录页面 完整L ...
- ASP.NET Core 中文文档 第三章 原理(7)配置
原文:Configuration 作者:Steve Smith.Daniel Roth 翻译:刘怡(AlexLEWIS) 校对:孟帅洋(书缘) ASP.NET Core 支持多种配置选项.应用程序配置 ...
- ASP.NET Core WebListener 服务器
原文地址:WebListener server for ASP.NET Core By Tom Dykstra, Chris Ross WebListener是一个只能运行在Windows上的ASP. ...
- ASP.NET Core的Kestrel服务器
原文地址----Kestrel server for ASP.NET Core By Tom Dykstra, Chris Ross, and Stephen Halter Kestrel是一个基于l ...
- ASP.NET Core 认证与授权[2]:Cookie认证
由于HTTP协议是无状态的,但对于认证来说,必然要通过一种机制来保存用户状态,而最常用,也最简单的就是Cookie了,它由浏览器自动保存并在发送请求时自动附加到请求头中.尽管在现代Web应用中,Coo ...
- [转帖]ASP.NET Core的Kestrel服务器
ASP.NET Core的Kestrel服务器 https://cloud.tencent.com/developer/article/1023247 在这篇文章中: 何时使用Kestrel和反向代理 ...
- ASP.NET Core的Kestrel服务器(转载)
Kestrel是一个基于libuv的跨平台ASP.NET Core web服务器,libuv是一个跨平台的异步I/O库.ASP.NET Core模板项目使用Kestrel作为默认的web服务器.Kes ...
- ASP.NET Core 配置文件
在ASP.NET Core 中,应用程序配置数据可以使用JSON, XML 和 INI格式 和内置环境变量,命令行参数或内存中的集合. 1.如何获取和设置配置 ASP.NET Core配置系统针对以前 ...
- 3.将模型添加到 ASP.NET Core MVC 应用
添加数据模型类 右键单击 Models 文件夹,然后单击“添加” > “类”. 将类命名“Movie”.向 Movie 类添加以下属性: using System;using System.Co ...
随机推荐
- labuladong数据结构
缓存淘汰算法:LRU①.LFU② BST③ 完全二叉树④ 序列化和反序列化二叉树⑤ 最近公共祖先⑥ 单调栈⑦ 单调队列⑧ 递归反转链表⑨ k个一组反转链表
- dos命令初学
DOS命令 打开DOS命令方式 开始+系统+命令提示符 WIN键盘+R 输入CMD 打开控制台(推荐使用) 在任意文件夹下面,按住shift键加鼠标右键点击,在此处打开命令行窗口 自愿管理器的地址栏前 ...
- 浙大版《C语言程序设计(第3版)》题目集 练习3-3 统计学生平均成绩与及格人数 (15 分)
练习3-3 统计学生平均成绩与及格人数 (15 分) 本题要求编写程序,计算学生们的平均成绩,并统计及格(成绩不低于60分)的人数.题目保证输入与输出均在整型范围内. 输入格式: 输入在第一行中给出非 ...
- Compose Modifier Clip 圆角
Row( modifier = Modifier .fillMaxWidth() .padding(20.dp) // 圆角 .clip(RoundedCornerShape(15.dp)) .cli ...
- 在CentOS下安装nginx+php环境
一.nginx 安装 1. 在nginx官网下载nginx源码 提供一个nginx官网下载地址: http://nginx.org/download/nginx-1.12.2.tar.gz 注意:请先 ...
- 使用MailKit发送邮件
MailKit的项目地址:https://github.com/jstedfast/MailKit 使用: 1 定义发送邮件所需要的model或者dto,该model可根据个人的需要进行修改 1 pu ...
- copy file from remote server to local
scp -r root@IP:/path/to/file(file path on the server) /path/to/filedestination(local path)
- 枚举类list序列化与反序列化
//序列化 public class AuthTypeEnumListJsonSerializer extends JsonSerializer<List> { @Override pub ...
- Spring Boot基础依赖
<properties> <java.version>1.8</java.version></properties><parent> < ...
- .NET dropdownlist控件绑定数据后,添加“全部”项,实现功能
DropDownList在从数据库中得到数据源绑定后,计划为其添加一个"全部"或"不限"之类的项,添加方法现知的有两种: 1:在脚本中直接添加:<asp: ...