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 whole appsettings.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; }
    }
๐Ÿ’ก
1. Property names must be same as configuration key name. 2. Constant Key is the section name in appsettings.json file. This is optional and you could have your section named as class name i.e. 'fileOptions' instead of 'file'.

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

๐Ÿ‘‰ The Options Pattern Simplified. Easily use your configuration in yourโ€ฆ | by Andre Lopes | Checkout.com-techblog | Medium

๐Ÿ‘‰ How To Use The Options Pattern In ASP.NET Core 7 (milanjovanovic.tech)

2
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

Deepak Kumar Jain
Deepak Kumar Jain