在 .NET Core 的配置系统中,IOptions<T>、IOptionsSnapshot<T> 和 IOptionsMonitor<T> 是用于将配置文件(如 appsettings.json)中的配置项注入到服务中的三种主要方式。它们的区别在于生命周期和配置更新行为。
📌 三者的定义与作用
1. IOptions<T>
- 生命周期:Singleton(单例)
- 特点:
- 配置在应用启动时读取一次,之后不会自动更新。
- 所有地方注入的
IOptions<T>都是同一个实例。 - 即使你修改了
appsettings.json文件并保存,已启动的应用也不会感知到变化。
- 适用场景:
- 配置项在应用运行期间几乎不变,如数据库连接字符串(虽然可以热更新,但
IOptions<T>不支持)。 - 性能要求高,且不需要动态更新配置。
- 配置项在应用运行期间几乎不变,如数据库连接字符串(虽然可以热更新,但
✅ 注册方式:自动支持,无需额外配置。
csharp
// 使用
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptions<MyConfig> options)
{
_config = options.Value;
}
}2. IOptionsSnapshot<T>
- 生命周期:Scoped(作用域)
- 特点:
- 每个请求(作用域)开始时读取一次配置。
- 如果你在
appsettings.json中修改了配置,并发起一个新请求,新请求会读取最新的配置。 - 在同一个请求内,多次获取
IOptionsSnapshot<T>得到的是同一个值。
- 适用场景:
- 配置可能在运行时更改,且你希望每个请求能获取最新的配置。
- Web 应用中最常用的配置注入方式。
✅ 注意:它依赖于文件的 reloadOnChange: true 设置。
json
// appsettings.json
{
"MyConfig": {
"ApiKey": "12345",
"Timeout": 30
}
}csharp
// Program.cs
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
// 使用
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptionsSnapshot<MyConfig> options)
{
_config = options.Value; // 每个请求获取一次最新值
}
}3. IOptionsMonitor<T>
- 生命周期:Singleton(单例)
- 特点:
- 可以实时监听配置变化,并在配置更新时触发回调。
- 提供
CurrentValue属性,始终返回最新值。 - 支持更改回调(
OnChange),可以在配置变化时执行逻辑(如重新加载缓存)。 - 支持命名选项(Named Options),即同一类型不同配置。
- 适用场景:
- 需要实时响应配置变化,如动态开关、限流阈值、功能启用等。
- 需要在配置更新时执行某些操作(如日志记录、缓存刷新)。
csharp
public class MyService
{
private readonly IOptionsMonitor<MyConfig> _options;
public MyService(IOptionsMonitor<MyConfig> options)
{
_options = options;
// 监听配置变化
_options.OnChange(config =>
{
Console.WriteLine($"配置已更新!新 API Key: {config.ApiKey}");
// 可以在这里刷新缓存、重新初始化服务等
});
}
public MyConfig GetCurrentConfig()
{
return _options.CurrentValue; // 始终是最新值
}
}🆚 三者对比总结
| 特性 | IOptions<T> | IOptionsSnapshot<T> | IOptionsMonitor<T> |
|---|---|---|---|
| 生命周期 | Singleton | Scoped | Singleton |
| 配置更新 | ❌ 不支持 | ✅ 每个请求更新 | ✅ 实时更新 |
| 是否触发回调 | ❌ | ❌ | ✅ 支持 OnChange |
| 同一请求内一致性 | ✅ | ✅ | ✅ |
| 跨请求共享 | ✅ | ❌(每请求不同) | ✅ |
| 适用场景 | 静态配置 | Web 请求级配置更新 | 实时监听 + 回调 |
✅ 如何选择?
| 场景 | 推荐使用 |
|---|---|
配置启动后不变(如 AppSettings:SiteName) | IOptions<T> |
| Web 应用,希望每个请求能读取最新配置 | IOptionsSnapshot<T> ✅(最常用) |
| 需要监听配置变化并执行逻辑(如动态开关) | IOptionsMonitor<T> |
| 多套同类型配置(如多个数据库配置) | IOptionsMonitor<T>(支持命名选项) |
💡 示例:配置文件热更新
json
// appsettings.json
{
"MyConfig": {
"ApiKey": "initial-key",
"FeatureEnabled": true
}
}csharp
// MyConfig.cs
public class MyConfig
{
public string ApiKey { get; set; }
public bool FeatureEnabled { get; set; }
}csharp
// 注册(自动支持)
builder.Services.Configure<MyConfig>(builder.Configuration.GetSection("MyConfig"));csharp
// 使用 IOptionsSnapshot(推荐 Web 项目)
public class ConfigController : ControllerBase
{
private readonly IOptionsSnapshot<MyConfig> _config;
public ConfigController(IOptionsSnapshot<MyConfig> config)
{
_config = config;
}
[HttpGet]
public IActionResult Get()
{
return Ok(_config.Value);
// 修改 appsettings.json 并保存后,刷新页面即可看到新值
}
}✅ 最佳实践
- 🌐 ASP.NET Core Web 项目:优先使用
IOptionsSnapshot<T>。 - ⚙️ 需要实时响应配置变化:使用
IOptionsMonitor<T>+OnChange。 - 🧱 静态配置、高性能场景:使用
IOptions<T>。 - 🔁 确保
reloadOnChange: true启用:
csharp
// Program.cs
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);总结
| 接口 | 用法 | 类比 |
|---|---|---|
IOptions<T> | 一次性读取,永不更新 | “只读一次” |
IOptionsSnapshot<T> | 每个请求读取一次 | “每请求刷新” |
IOptionsMonitor<T> | 实时监听,随时获取最新值 | “订阅模式” |
在大多数 Web 项目中,IOptionsSnapshot<T> 是最常用的选择,因为它平衡了性能和灵活性。