Difference between IOptionsMonitor vs. IOptionsSnapshot

natenho picture natenho · Jun 11, 2018 · Viewed 9.1k times · Source

According to this answer, IOptionsMonitor is registered in DI container as singleton and is capable of detecting changes through OnChange event subscription. It has a CurrentValue property.

In the other hand, IOptionsSnapshot is registered as scoped and also have a change detection capability by reading the last options for each request, but it doesn't have the OnChange event. It has a Value property.

Using both injected into a view for instance gives us the exactly same behavior:

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}";
        }
    }
}

So, what's the point of having these two interfaces/implementation if they look like the same thing, just with different life times? The code is based on this sample, which surprisinly doesn't include an IOptionsMonitor usage sample.

Why one have a "Value" property and other have "CurrentValue" if both gets the "current value" of an option?

Why/when should I use IOptionsSnapshot instead of IOptionsMonitor?

I don't think I got it straight, I must be missing some very important aspect regarding these dependencies injection.

Answer

Paul Miller picture Paul Miller · Sep 29, 2018

The comments have some pretty good answers already to try and summarize/repeat Tseng.

IOptionsSnapshot is great for getting injected into an object that is scoped or transient. It will be consistent of the lifetime of that object and new values will come in as you get new objects.

However if you need options that reload in a singleton IOptionsMonitor is what you should use because your singleton will never change. A good example of such services are those inherited from IHostedService, for long-running background services in Asp.net Core.