當前文章的短網址連結為: https://unos.top/sp3v
两者的主要区别体现在生命周期、配置重新加载和对配置变更的感知上。
| 特性 | IOptions<TOptions> | IOptionsSnapshot<TOptions> |
|---|---|---|
| 生命周期 | 单例 | 作用域 |
| 配置重新加载 | 不支持。在应用启动时加载一次,之后不会更改。 | 支持。在每个作用域内,它会与当前配置源(如 appsettings.json)同步,读取最新值。 |
| 变更感知 | 不感知配置文件的更改。 | 感知更改。每次从新的作用域解析时,都会提供最新的配置数据。 |
| 主要用途 | 用于在应用整个生命周期内不会改变的配置。 | 用于需要响应运行时配置更改的场景(如云环境、功能开关)。 |
| 性能 | 最佳。只计算一次。 | 每次创建新作用域时有微小开销,因为它会重新绑定配置。 |
| 错误处理 | 在应用启动时验证并绑定配置,如果配置错误,应用会立即失败。 | 在每次解析时验证,错误可能延迟到请求处理时才暴露。 |
详细解释与示例
假设你有以下配置类:
public class MySettings
{
public string ApiEndpoint { get; set; }
public int Timeout { get; set; }
}C#在 Startup/Program.cs中配置:
builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings"));C#1. 使用 IOptions<>(单例,不可变)
public class MyService
{
private readonly MySettings _settings;
// 注入 IOptions<MySettings>,它是一个单例
public MyService(IOptions<MySettings> options)
{
// 只在构造函数中读取一次值
_settings = options.Value; // 此值在整个应用生命周期内保持不变
}
}C#行为:即使你在应用运行时修改了 appsettings.json文件,_settings中的值也不会更新。它持有的是应用启动时的快照。
2. 使用 IOptionsSnapshot<>(作用域,可重新加载)
public class MyController : ControllerBase
{
private readonly MySettings _settings;
// 注入 IOptionsSnapshot<MySettings>,它的生命周期是“作用域”
public MyController(IOptionsSnapshot<MySettings> optionsSnapshot)
{
// 每次构造控制器(即每个HTTP请求)时,都会读取最新的配置
_settings = optionsSnapshot.Value; // 此值会反映最新的配置文件内容
}
}C#行为:每个传入的 HTTP 请求(即每个作用域),optionsSnapshot.Value都会从当前的配置源重新加载并绑定数据。如果你在请求间隔中修改了配置文件,下一个请求将获取到新值。
如何选择?
- 使用
IOptions<>:当你的配置在应用启动后绝对不变时。这是最常见和最高效的用法,适用于数据库连接字符串、功能标志的初始设置等。 - 使用
IOptionsSnapshot<>:当你需要在应用运行时动态改变配置而不重启应用时。这在云原生环境、使用 Azure App Configuration 或需要“热重载”配置的场景中非常有用。
另外一个重要的相关接口:IOptionsMonitor<>
除了上述两者,还有一个更高级的接口 IOptionsMonitor<>:
- 生命周期:单例。
- 行为:它主动监听配置源的变更,并通过
OnChange事件提供回调机制。你可以通过CurrentValue属性获取当前最新的配置值。 - 用途:用于后台服务或单例服务中,需要持续获取最新配置,并对配置变更做出即时反应的场景。
public class MyBackgroundService : BackgroundService
{
private readonly IOptionsMonitor<MySettings> _monitor;
public MyBackgroundService(IOptionsMonitor<MySettings> monitor)
{
_monitor = monitor;
// 注册一个当配置改变时的回调函数
_monitor.OnChange(newSettings =>
{
Console.WriteLine($"配置已更新!新端点: {newSettings.ApiEndpoint}");
});
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// 始终从单例的 Monitor 中获取当前值
var currentSettings = _monitor.CurrentValue;
// ... 使用 currentSettings 工作
await Task.Delay(5000, stoppingToken);
}
}
}C#总结
| 接口 | 生命周期 | 配置更新 | 典型的使用场景 |
| IOptions<> | 单例 | 否 | 启动后不变的全局配置 |
| IOptionsSnapshot<> | 作用域 | 是(按作用域) | Web API/控制器中,需要每个请求都读取最新配置 |
| IOptionsMonitor<> | 单例 | 是(实时监听) | 后台服务、单例服务,需要监听配置变更事件 |
