在 .NET 10 LTS 中,IOptions<TOptions>和 IOptionsSnapshot<TOptions>的主要区别

  • Post author:
  • Post category:C#
  • Post comments:0评论
當前文章的短網址連結為: 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<>​单例是(实时监听)后台服务、单例服务,需要监听配置变更事件

0 0 投票数
文章评分
订阅评论
提醒
guest

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论