Options pattern in ASP.NET Core

The options pattern uses classes to represent groups of related settings.

Category Fundamentals

Published: 24 November 2018

The options pattern uses classes to represent groups of related settings. When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

View or download sample code (how to download) This article is easier to follow with the sample app.


Prerequisites

Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Options.ConfigurationExtensions package.


Basic options configuration

Basic options configuration is demonstrated as Example #1 in the sample app.

An options class must be non-abstract with a public parameterless constructor. The following class, MyOptions, has two properties, Option1 and Option2. Setting default values is optional, but the class constructor in the following example sets the default value of Option1. Option2 has a default value set by initializing the property directly (Models/MyOptions.cs):

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

 

The MyOptions class is added to the service container with Configure<TOptions>(IServiceCollection, IConfiguration) and bound to configuration:

// Example #1: Basic options
// Register the Configuration instance which MyOptions binds against.
services.Configure<MyOptions>(Configuration);

 

The following page model uses constructor dependency injection with IOptions<TOptions> to access the settings (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
IOptions<MyOptions> optionsAccessor,
IOptions<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig,
IOptions<MySubOptions> subOptionsAccessor,
IOptionsSnapshot<MyOptions> snapshotOptionsAccessor,
IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.Value;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.Value;
    _subOptions = subOptionsAccessor.Value;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #1: Simple options
var option1 = _options.Option1;
var option2 = _options.Option2;
SimpleOptions = $"option1 = {option1}, option2 = {option2}";

 

The sample's appsettings.json file specifies values for option1 and option2:

{
    "option1": "value1_from_json",
    "option2": -1,
    "subsection": {
        "suboption1": "subvalue1_from_json",
        "suboption2": 200
    },
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "AllowedHosts": "*"
}



When the app is run, the page model's OnGet method returns a string showing the option class values:

option1 = value1_from_json, option2 = -1