Asp.net core IOptionsMonitor与IOptionsSnapshot之间的差异

Asp.net core IOptionsMonitor与IOptionsSnapshot之间的差异,asp.net-core,dependency-injection,interface,options,object-lifetime,Asp.net Core,Dependency Injection,Interface,Options,Object Lifetime,根据,IOptionsMonitor在DI容器中注册为singleton,并且能够通过OnChange事件订阅检测更改。它有一个CurrentValue属性 另一方面,IOptionsSnapshot被注册为作用域,并且还具有通过读取每个请求的最后选项进行更改检测的功能,但它没有OnChange事件。它有一个值属性 例如,在视图中使用这两种方法会产生完全相同的行为: using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extens

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


另一方面,
IOptionsSnapshot
被注册为作用域,并且还具有通过读取每个请求的最后选项进行更改检测的功能,但它没有
OnChange
事件。它有一个
属性

例如,在视图中使用这两种方法会产生完全相同的行为:

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}";
        }
    }
}
使用Microsoft.AspNetCore.Mvc.RazorPages;
使用Microsoft.Extensions.Options;
使用选项sample.Models;
使用UsingOptionsSample.Services;
命名空间UsingOptionsSample.Pages
{
公共类选项
{
公共选项()
{
//设置默认值。
Option1=“value1\u from\u ctor”;
}
公共字符串选项1{get;set;}
公共int选项2{get;set;}=5;
}
公共类选项TestModel:PageModel
{
私有只读MyOptions\u快照选项;
私有只读MyOptions\u监视器选项;
公共选项测试模型(
IOPTIONS监视器监视器选项转换器,
IOptionsSnapshot快照选项访问器)
{
_snapshotOptions=snapshotOptions访问器.Value;
_monitorOptions=MonitorOptionAccessor.CurrentValue;
}
公共字符串快照选项{get;private set;}
公共字符串监视器选项{get;private set;}
公共无效OnGetAsync()
{
//快照选项
var snapshotOption1=\u snapshotOptions.Option1;
var snapshotOption2=\u snapshotOptions.Option2;
快照选项=
$“快照选项1={snapshotOption1},”+
$“快照选项2={snapshotOption2}”;
//监视器选项
var monitorOption1=\u monitorOptions.Option1;
var monitorOption2=\u monitorOptions.Option2;
监视器选项=
$“监视器选项1={monitorOption1},”+
$“监视器选项2={monitorOption2}”;
}
}
}
那么,如果这两个接口/实现看起来是一样的,只是生命周期不同,那么拥有这两个接口/实现又有什么意义呢?代码是,令人惊讶的是,它没有包含
IOptionsMonitor
usage示例

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


为什么/何时应该使用
IOptionsSnapshot
而不是
IOptionsMonitor


我不认为我是直截了当的,我肯定错过了一些关于这些和依赖注入的非常重要的方面。

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


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


但是,如果您需要在单例中重新加载选项,则应该使用
IOptionsMonitor
,因为您的单例永远不会更改。此类服务的一个很好的例子是继承自ASP.NET Core中长期运行的后台服务的
IHostedService

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


IOptionsSnapshot
是一项范围服务,在构建
IOptionsSnapshot
对象时提供选项的快照。选项快照设计用于瞬态依赖项和作用域依赖项

当您不希望配置值更改时,请使用
IOptions
改变当您希望您的值符合要求时,请使用
IOptionsSnaphot
更改,但希望它在整个请求中保持一致。使用
IOptionsMonitor
当您需要实时值时


IOptionsSnapshot
有一个作用域生存时间,以确保在单个请求期间具有相同的配置值。如果mid请求中的内容发生更改,这可能是一种奇怪的行为。然后,请求的一部分将应用旧值,更改后的第二部分将应用新值,导致冲突和难以跟踪错误。对于与请求相关(或在请求过程中执行)的所有内容,您应该使用snappshot@Tseng:但是
IOptionsMonitor
添加了哪些
IOptionsSnapshot
没有添加的内容?为什么要选择监视器?监视器基本上是用于通知的,而快照是
IOptionsMonitor
的缓存版本/快照,在请求过程中不会更改,例如<如果将代码>IOptionsSnapshot注入到单例服务中,它将不起作用。中介绍了与IOptions的差异