Options pattern in ASP.NET Core: Introduction
In this article we will learn about Options pattern in ASP.NET Core for dealing with application configurations. The Options pattern uses the C# classes to access and manage the configurations thus providing more flexibility and type safe approach to manage application configurations.
if you are already familiar with Options pattern and want to understand about some advance scenario handled by this pattern then please refer another article : Options pattern in ASP.NET Core: Advance scenario
Application's setting or configuration could come from multiple sources:
JSON files -
appsettings.json
or any other JSON file.Environment variables
Command lines arguments.
Other sources like from DB, from xml file, from INI files etc.
Let's dive into code to solidify the understanding.
GitHub repo link for the code sample: dkj468/OptionsPatternDemo (github.com)
Let's assume we have some application configurations defined in appsettings.json
file:
"file": {
"maxSize": "2Mib",
"fileType": "pdf;jpeg;",
"canModify": false,
"maxFileCount": 5
}
Our aim is to read this configuration data and use it throughout the application. There are multiple ways to read this data from appsettings.json
in ASP.NET Core applications. Here, we will start with basic way which is to use IConfiguration
interface and then will explore the Options pattern to achieve the same thing.
Reading configuration data using IConfiguration
appsettings.json
content can be read easily using IConfiguration
interface. We simply need to inject an instance of IConfiguration
into controller constructor and all the config values are accessible to use.
public class FileController : ControllerBase {
private readonly IConfiguration _config;
public FileController (IConfiguration config) {
_config = config;
}
[HttpGet("config/iconfiguration")]
public IActionResult GetFileConfig_IConfiguration() {
var fileSize = _config.GetValue<string>("file:maxSize");
var fileType = _config.GetValue<string>("file:fileType");
var canModify = _config.GetValue<bool>("file:canModify");
var maxFileCount = _config.GetValue<int>("file:maxFileCount");
return Ok(new { fileSize = fileSize, fileType = fileType, canModify = canModify, maxFileCount = maxFileCount });
}
}
Reading config data using IConfiguration
is straightforward and doesn't require any rocket science in ASP.NET Core code. However, this approach has some problems such as:
Security:
IConfiguration
has access to wholeappsettings.json
contents thus exposing the other settings as well.Code maintainability: configuration key must be named and used properly to avoid mistakes.
No validation: There is no mechanism to validate configurations with
IConfiguration
No type safety:
IConfiguration
reads configuration values as string and those strings must be parsed manually to appropriate type.No default value: There is no mechanism to have a default value for a configuration.
No reload on change: sometimes there are requirements to reload the changed configurations. with
IConfiguration
this can't be achieved.
As explained above, managing configurations using IConfiguration
is straightforward but comes with some limitations. Now let's explore Options pattern to overcome all above shortcomings.
Reading Configuration data using Options pattern
There are 3 steps involved in using Options pattern:
Defining a C# class which represents a mapping of configuration data.
Binding the C# class with intended section of configuration file and registering it with services container
Injecting the
IOptions
interface via constructor injection to use it.
Let's see this in action using code.
First, we will create a C# class representing the configuration data.
public class FileOptions {
public const string Key = "file";
public string MaxSize { get; set; }
public string FileType { get; set; }
public bool CanModify { get; set; }
public int MaxFileCount { get; set; }
}
Second, we will bind the FileOptions
class with file
section of the configuration file and will register it with IServiceCollection
inside Program.cs
file.
builder.Services
.Configure<FileOptions>(builder.Configuration.GetSection("file"));
There is another way to bind the configuration with Options class which is to use AddOptions
extension method.
builder.Services
.AddOptions<FileOptions>().Bind(builder.Configuration.GetSection("file"));
The later returns a OptionsBuilder<T>
which allows to chain the configuration for advance scenario like handling custom validations, validations during startup of the application etc. We will discuss it further in upcoming article.
Third and final step, we will use this FileOptions
options inside a controller to fetch the configuration data.
public class FileController : ControllerBase {
private readonly IConfiguration _config;
private readonly FileOptions _fileOptions;
public FileController(IConfiguration config, IOptions<FileOptions> fileOptions) {
_config = config;
_fileOptions = fileOptions.Value;
}
[HttpGet("config/iconfiguration")]
public IActionResult GetFileConfig_IConfiguration() {
var fileSize = _config.GetValue<string>("file:maxSize");
var fileType = _config.GetValue<string>("file:fileType");
var canModify = _config.GetValue<bool>("file:canModify");
var maxFileCount = _config.GetValue<int>("file:maxFileCount");
return Ok(new { fileSize = fileSize, fileType = fileType, canModify = canModify, maxFileCount = maxFileCount });
}
// get config data using Options Pattern
[HttpGet("config/option")]
public IActionResult GetFileConfig_IOptions() {
var fileSize = _fileOptions.MaxSize;
var fileType = _fileOptions.FileType;
var canModify = _fileOptions.CanModify;
var maxFileCount = _fileOptions.MaxFileCount;
return Ok(new { fileSize = fileSize, fileType = fileType, canModify = canModify, maxFileCount = maxFileCount });
}
}
In above code, we have injected IOptions
with type FileOptions
. Notice that Value
property of IOptions
interface returns an instance of FileOptions
There are some advance scenarios which could be handled easily with Options pattern for example:
validation of configuration.
validating the configuration values during application start-up.
handling command line arguments or environment variables using Options pattern.
monitoring for changes into configuration data etc.
This article aimed to explore the fundamental of Options pattern. In upcoming articles, we will explore how to handle above mentioned scenarios using this pattern.
Conclusion
In this article we have explored how to read application configuration using basic way i.e. using IConfiguration
and later learned about Options pattern to achieve the same thing. On the surface, it seems an overkilling to use this pattern for the simple use case, but Options pattern has helped us achieving below things:
๐ฅ type safety and manageable code: no more hard coded strings into code. Easy to change the configuration key names.
๐ฅ Separation of concerns: Bind only related config and hide other details of configuration settings.
That's it for this article, In next article we will explore some advance use cases solved using Options pattern.
References and motivation
๐ Options pattern - .NET | Microsoft Learn
๐ Options Pattern inASP.NETCore โ Bind & Validate Configurations from appsettings.json - codewithmukesh
๐ How To Use The Options Pattern In ASP.NET Core 7 (milanjovanovic.tech)
Subscribe to my newsletter
Read articles from Deepak Kumar Jain directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by