Application configuration
.NET .NET Core Best Practices C# Dependency Injection Patterns Visual Studio

Using the IOptions Pattern in a .NET Core Application

Hi and welcome back to my blogs on development!

Today I will go over how you can use the IOptions pattern in a .NET Core application.

We can use this pattern in both a .NET Core Web application and a .NET Core Web API.

With almost all applications we require the use of a configuration file to store settings that are required to configure various settings that are required to allow our application components to integrate with the various on-premises and cloud-based services that is uses.

The way we learnt to use application settings was to directly read off the settings within our application by referencing a settings key name. Each settings key name has an associated value that is stored in the configuration file as a string. We would then parse the value as a type (string, integer, float) and then use that value. The value would then be used within our application to change the look of the application interface or determine integrations to a backend service (such as a database, web API, or cloud service).

When to use the IOptions Pattern

Instead of hard-coding settings key names within our application, we can reference the settings keys through a typed DTO class that contains as properties corresponding to each of the settings keys. To be able to map settings keys to class properties and their values we can inject application settings within your .NET Core applications using dependency injection in .NET Core 3.1. The ability to inject settings keys and their respective values from a configuration file into a DTO class is a much cleaner coding technique and this is known as the IOptions pattern.

The file used to store configuration settings for our .NET Core web application is the appsettings.json file. A sample format of this file is shown as follows:

{
  "ConnectionStrings": {
    "AppDbContext": "[some connection string]"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AppSettings": {
    "AppName": "BookLoan",
    "AppVersion": "1.0.0",
    "AlertEmail": operator@bookloan.com,
    "UrlCatalogAPI": "http://localhost/BookLoan.Catalog.API/",
    "UrlLoanAPI": "http://localhost/BookLoan.Loan.API/"
  }
}

To obtain a connection string, we can use the following command:

string dbConnStr = Configuration.GetConnectionString("AppDbContext")

where Configuration is injected through a constructor, e.g. from Startup():

public IConfiguration Configuration { get; }

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

This is quite straightforward, and similar to traditional .NET 4.x Framework applications.

How about the key / value pairs in the AppSettings section?

The following will also work:

string sAppName = Configuration.GetValue<string>("AppSettings:AppName");
string sAppVersion = Configuration.GetValue<string>("AppSettings:AppVersion");

If we had numerous settings key / values to retrieve into our service classes, the above would be quite cumbersome and repeat itself. The solution to this is to use the IOptions pattern from .NET Core framework 2.2/3.1.  The IOptions pattern allows us to make configuration access strongly types by mapping application settings into a concrete application type model instance that is accessible through the use of dependency injection anywhere within our application classes.

Configuration and Implementation of the IOptions Pattern

Once we have decided to use IOptions within our application, we will then need to configure our .NET Core application to map the key value pairs from the configuration file into the properties of a custom configuration DTO class.

In the steps that I will outline below, step 2 shows the configurations required within our .NET Core startup. Step 1 shows the custom DTO class definition and the remaining steps, 3 and 4 detail examples of the coding required to integrate and inject the options pattern into our service classes.  

These are the steps to take to use IOptions:

Step 1. Define a custom configuration class

Create a class to containing your application settings:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BookLoan.Services
{
    public class AppConfiguration
    {
        public AppConfiguration() { } 
        public string AppName { get; set; } 
        public string AppVersion { get; set; } 
        public string UrlCatalogAPI { get; set; }
        public string UrlLoanAPI { get; set; }
    }
}

Step 2. Changes to ConfigureServices()

In your ConfigureServices() method within startup.cs add the following two lines:

public void ConfigureServices(IServiceCollection services)
{
    …            
    services.Configure<AppConfiguration>(
        Configuration.GetSection("AppSettings"));
		…
}

We include the following namespace at the top of the source.

Microsoft.Extensions.Configuration

By including the options pattern into your services container, allows your application to map the equivalent settings from appSettings.json into your application configuration model.

Step 3. Injection of IOptions into Service Classes

Inject IOptions into a custom service class. Reference the configuration data within your service class and obtain settings properties:

using Microsoft.Extensions.Options;
…

public class BookService: IBookService
{
    …
    private readonly IOptions<AppConfiguration> _appConfiguration;

    public BookService(..., IOptions<AppConfiguration> appConfiguration, …)
    {
        ...
        _appConfiguration = appConfiguration;
    }
    …

Step 4. Reading Configuration Values from the Options Manager

Obtain the application configuration value from the options manager:

public async Task<List<BookViewModel>> GetBooks()
{
    ...

    HttpResponseMessage response = null;
    var delayedRetry = _apiServiceRetryWithDelay;

    await delayedRetry.RunAsync(async () =>
    {
        response = await _apiServiceHelper.GetAPI(
            _appConfiguration.Value.UrlCatalogAPI + "api/Book/List",
            null,
            bearerToken
        );
    });
    ...

Use of the IOptions pattern gives you a cleaner way to inject application configuration settings into your application classes and handles the lifetime of the application configuration data for you.

In addition, it makes the configuration access strongly typed.

That’s all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial