Learning the building blocks – Options, Settings, and Configuration

There are four main interfaces to use settings: IOptionsMonitor<TOptions>, IOptionsFactory<TOptions>, IOptionsSnapshot<TOptions>, and IOptions<TOptions>. We must inject that dependency into a class to use the available settings. TOptions is the type that represents the settings that we want to access.The framework returns an empty instance of your options class if you don’t configure it. We learn how to configure options properly in the next subsection; meanwhile, remember that using property initializers inside your options class can also be a great way to ensure certain defaults are used. You can also use constants to centralize those defaults somewhere in your codebase (making them easier to maintain). Nevertheless, proper configuration and validation are always preferred, but both combined can add a safety net. Don’t use initializers or constants for default values that change based on the environment (dev, staging, or production) or for secrets such as connection strings and passwords.

You should always keep secrets out of your Git history, whether it’s out of the C# code or out of setting files. Use ASP.NET Core secrets locally and a secret store like Azure KeyVault for Staging and Production environments.

If we create the following class, since the default value of an int is 0, the default number of items to display per page would be 0, leading to an empty list.

public class MyListOption
{
    public int ItemsPerPage { get; set; }
}

However, we can configure this using a property initializer, as next:

public class MyListOption
{
    public int ItemsPerPage { get; set; } = 20;
}

The default number of items to display per page is now 20.

In the source code for this chapter, I’ve included a few tests in the CommonScenarios.Tests project that assert the lifetime of the different options interfaces. I haven’t included this code here for brevity, but it describes the behavior of the different options via unit tests. See https://adpg.link/AXa5 for more information.

The options served by each interface have different DI lifetimes and other features. The following table exposes some of those features:

InterfaceLifetimeSupport named optionsSupport change notification
IOptionsMonitor<TOptions>SingletonYesYes
IOptionsFactory<TOptions>TransientYesNo
IOptionsSnapshot<TOptions>ScopedYesNo
IOptions<TOptions>SingletonNoNo

 Table 9.1: The different options interfaces, their DI lifetime, and support for other features.

Next, we explore those interfaces more in-depth.

IOptionsMonitor<TOptions>

This interface is the most versatile of them all:

  • It supports receiving notifications about reloading the configuration (like when the setting file changed).
  • It supports caching.
  • It supports named configuration (identifying multiple different TOptions with a name).
  • The injected IOptionsMonitor<TOptions> instance is always the same (singleton lifetime).
  • It supports unnamed default settings through its Value property.

If we only configure named options or no instance at all, the consumer will receive an empty TOptions instance (new TOptions()).

Leave a Reply

Your email address will not be published. Required fields are marked *



         


          Terms of Use | Accessibility Privacy