IOptionsMonitor 与 IOptionsSnapshot 之间的区别

问题描述 投票:0回答:4

根据这个答案

IOptionsMonitor
在DI容器中注册为singleton,并且能够通过
OnChange
事件订阅检测更改。它具有
CurrentValue
属性。

另一方面,

IOptionsSnapshot
注册为 scoped,并且还具有通过读取每个请求的最后选项来进行更改检测的功能,但它没有
OnChange
事件。它具有
Value
属性。

例如,使用两者注入视图可以给我们带来完全相同的行为:

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;
using UsingOptionsSample.Models;
using UsingOptionsSample.Services;

namespace UsingOptionsSample.Pages
{
    public class MyOptions
    {
        public MyOptions()
        {
            // Set default value.
            Option1 = "value1_from_ctor";
        }
        
        public string Option1 { get; set; }
        public int Option2 { get; set; } = 5;
    }

    public class OptionsTestModel : PageModel
    {
        private readonly MyOptions _snapshotOptions;
        private readonly MyOptions _monitorOptions;
        
        public OptionsTestModel(
            IOptionsMonitor<MyOptions> monitorOptionsAcessor, 
            IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
        {
            _snapshotOptions = snapshotOptionsAccessor.Value;
            _monitorOptions = monitorOptionsAcessor.CurrentValue;
        }

        public string SnapshotOptions { get; private set; }
        public string MonitorOptions { get; private set; }

        public void OnGetAsync()
        {
             //Snapshot options
            var snapshotOption1 = _snapshotOptions.Option1;
            var snapshotOption2 = _snapshotOptions.Option2;
            SnapshotOptions =
                $"snapshot option1 = {snapshotOption1}, " +
                $"snapshot option2 = {snapshotOption2}";

            //Monitor options
            var monitorOption1 = _monitorOptions.Option1;
            var monitorOption2 = _monitorOptions.Option2;
            MonitorOptions =
                $"monitor option1 = {monitorOption1}, " +
                $"monitor option2 = {monitorOption2}";
        }
    }
}

那么,如果这两个接口/实现看起来像相同的东西,只是具有不同的生命周期,那么它们有什么意义呢?该代码基于此示例,令人惊讶的是它不包含

IOptionsMonitor
使用示例。

如果两者都返回选项的“当前值”,为什么一个具有“Value”属性而另一个具有“CurrentValue”?

为什么/何时应该使用

IOptionsSnapshot
而不是
IOptionsMonitor

我认为我没有弄清楚,我一定错过了有关这些和依赖注入的一些非常重要的方面。

asp.net-core dependency-injection interface object-lifetime
4个回答
75
投票

IOptionsMonitor
是一个单例服务,可以随时检索当前选项值,这在单例依赖项中特别有用。

IOptionsSnapshot
是一个范围服务,并在构建 IOptionsSnapshot<T> 对象时提供选项的
快照
。选项快照设计用于与transientscoped依赖项一起使用。

当您不希望配置值出现时,请使用

IOptions<T>
改变。当您期望您的价值观时,请使用
IOptionsSnaphot<T>
更改但希望它在整个请求中保持一致。使用
IOptionsMonitor<T>
当您需要实时值时。


29
投票

评论已经有一些很好的答案了。尝试总结/重复曾:

IOptionsSnapshot
非常适合注入到作用域或瞬态的对象中。它将在该对象的生命周期内保持一致,并且当您获得新对象时将出现新值。

但是,如果您需要在单例中重新加载的选项,则应该使用

IOptionsMonitor
,因为您的单例永远不会改变。此类服务的一个很好的例子是那些继承自
IHostedService
的服务,用于 ASP.NET Core 中长期运行的后台服务。


0
投票

我认为主要原因是你想要保留原始更改还是获得动态配置更改。

IOptionsSnapshot 允许您从特定时间点(“快照”)访问配置。由于配置可能会动态更改(无需重新启动应用程序),因此IOptionsSnapshot是在注册时保留原始配置的好方法。

另一方面,

IOptionsMonitor提供了一种跟踪和获取当前配置以及在运行时动态重新加载更改时更新此配置的方法。


-1
投票

在我的项目中,我需要从配置中读取一些值并将它们与身份验证令牌数据合并。因此,我使用

IOptionsSnapshot
进行范围存储,并且必须更新只读
Value
属性。没问题,更新每个属性:

IOptionsMonitor<Company> companyConfig
  ...
  _companyConfig.Value.CompanyName = "...";
© www.soinside.com 2019 - 2024. All rights reserved.