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.
On the other hand, IOptionsSnapshot
is registered as scoped and also has 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 exact 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/implementations if they look like the same thing, just with different lifetimes? The code is based on this sample, which surprisingly doesn't include an IOptionsMonitor
usage sample.
Why does one have a "Value" property and the other have a "CurrentValue" if both return 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 and dependency injection.
IOptionsSnapshot
has a scoped life time to guarantee you have the same configuration values during a single request. It could be odd behavior if the content changes in the mid request. Then one part of your request would apply the old values and the second part after the changes would apply new values, leading to conflicts and hard to track bugs. For everything that's related (or executed during) a request, you should use the snappshot – DalhousieIOptionsMonitor<T>
add thatIOptionsSnapshot<T>
doesn't? Why would one chose the monitor? – LadyfingerIOptionsMonitor<T>
and doesnt change during the request – DalhousieIOptionsSnapshot<T>
won't work if you inject it into a singleton service – Dalhousie