Options pattern is a powerful and versatile configuration method in .NET, particularly in ASP.NET. It allows developers to group related settings into coherent classes, facilitating the management and injection of configurations throughout the application code.
Implementation
Creating and implementing the Options pattern follows a series of key steps. First, we need to add in the settings file appsettings.json
or appsettings.{Environment}.json
the values we need:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MyOptions": {
"Options1": "hello world",
"Options2": 12
}
}
Subsequently, it's necessary to define a class for the settings:
public class MyOptions
{
public string? Option1 { get; set; }
public int Option2 { get; set; }
}
These settings must be configured in the Program.cs
file:
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));
Finally, the settings can be injected into the necessary parts of the application via dependency injection.
public class MyService
{
private readonly MyOptions _myOptions;
public MyService(IOptions<MyOptions> myOptionsAccessor)
{
_myOptions = myOptionsAccessor.Value;
}
}
Read the configuration settings
To access configuration settings, you can use one of these two methods:
-
GetSection(string key)
: Returns anIConfigurationSection
that represents a specific part of the configuration settings from the provided key. If the section isn't found in the configuration settings, this method will not throw an exception but rather will return a section with no value. -
GetRequiredSection(string key)
: Similar toGetSection
, it also returns anIConfigurationSection
representing a specific part of the configuration settings from the provided key. However, if the section isn't found in the configuration settings,GetRequiredSection
will throw an exception (InvalidOperationException
).
IOptions, IOptionsSnapshot, and IOptionsMonitor
Once the Options pattern is implemented, there are three main interfaces that can be used to access the options: IOptions<T>
, IOptionsSnapshot<T>
, and IOptionsMonitor<T>
. Each of these interfaces has a specific use case and provides unique advantages.
-
IOptions: This is the simplest way to access the options. The
IOptions<T>
instance is created at the application's start and remains the same for the duration of the application. It does not detect changes to the configuration settings during the application's runtime. -
IOptionsSnapshot: This interface is particularly useful in ASP.NET applications that handle multiple simultaneous requests.
IOptionsSnapshot<T>
creates a new instance of the options for each request, meaning it can detect changes to configuration settings between different requests. -
IOptionsMonitor:
IOptionsMonitor<T>
is similar toIOptionsSnapshot<T>
in that it can detect changes to configuration settings. However, unlikeIOptionsSnapshot<T>
, it does not create a new instance of the options for each request. Instead, it uses a notification mechanism to update the options when it detects a change. This makes it more efficient thanIOptionsSnapshot<T>
when settings change rarely.
The comparison between these three interfaces fundamentally comes down to the frequency of changes to configuration settings and the need to detect these changes. If your settings never change during the application's runtime, IOptions<T>
is probably the best choice. If your settings change frequently and you need to detect these changes for every request, then IOptionsSnapshot<T>
might be the best choice. If your settings change but not very frequently, IOptionsMonitor<T>
offers a good balance between updating settings and efficiency.
Benefits
Options pattern offers some advantages:
- It brings together related settings: Settings that are logically related can be grouped together in a single class. This makes the code more readable and easier to manage.
- Provides strong typing of settings: Settings are strongly typed, which means you will get IntelliSense support and type checks at compile time.
- Facilitates testing: Settings can be easily faked in tests, which makes it easier to write unit tests.
Named Options and Post-configuration
To handle more complex configurations, the Options pattern also provides support for named options and post-configuration.
Named options allow for configuring different instances of the same options class. This is particularly useful if you need to use different sets of configurations within the same application.
builder.Services.Configure<MyOptions>("option1", builder.Configuration.GetSection("Option1"));
builder.Services.Configure<MyOptions>("option2", builder.Configuration.GetSection("Option2"));
Named options can then be retrieved using IOptionsSnapshot<T>
or IOptionsMonitor<T>
.
public class MyService
{
private readonly MyOptions _option1;
private readonly MyOptions _option2;
public MyService(IOptionsSnapshot<MyOptions> options)
{
_option1 = options.Get("option1");
_option2 = options.Get("option2");
}
}
Post-configuration provides the ability to configure the options after they have been initialized within the Program.cs
file. This is useful if you need to set some options based on others.
builder.Services.PostConfigure<MyOptions>(options =>
{
if (string.IsNullOrEmpty(options.Option1))
{
options.Option1 = "Default Value";
}
});
In this example, if Option1
has not been configured, it is set to "Default Value".
Options validation
Options pattern supports options validation. You can create a validation class by implementing the IValidateOptions
interface. For instance:
using Microsoft.Extensions.Options;
public class MyOptionsValidation : IValidateOptions<MyOptions>
{
public ValidateOptionsResult Validate(string name, MyOptions options)
{
return string.IsNullOrEmpty(options.Option1)
? ValidateOptionsResult.Fail("Option1 is required.")
: ValidateOptionsResult.Success;
}
}
Then, you can register this validation class in the Program.cs
file:
using Microsoft.Extensions.Options;
builder.Services.AddSingleton<IValidateOptions<MyOptions>, MyOptionsValidation>();
If the settings do not pass validation, the application throws an exception at startup.
Conclusion
Options pattern in ASP.NET provides a powerful configuration method. It allows grouping settings into strongly typed classes, offers the ability to monitor changes to settings, supports settings validation, and more. Depending on your specific needs, IOptions<T>
, IOptionsSnapshot<T>
and IOptionsMonitor<T>
offer various ways to handle and access your configuration settings.
Top comments (2)
Nice!
Thank you 🙏