Reading Configurations in ASP.NET 8 with the IOptions Pattern and its types

Introduction:

In modern ASP.NET applications, managing configurations is crucial for setting up application-specific settings like database connection strings, API keys, or feature flags. The IOptions pattern is the recommended approach for accessing configuration settings in a strongly-typed manner. In this post, we’ll walk through how to use the IOptions pattern in ASP.NET 8 to manage and read configurations effectively.


What is the IOptions Pattern?

The IOptions pattern in ASP.NET Core allows you to bind configuration settings to strongly-typed classes and access them throughout the application. It provides a clean and testable way to manage application settings, as well as the ability to reload configurations at runtime when they change.


Benefits of Using IOptions:

  1. Type Safety: You can bind your settings to classes, making them strongly typed and easy to work with.
  2. Separation of Concerns: Your application logic can be cleanly separated from the configuration, reducing the risk of hardcoded values.
  3. Scalability: Supports hierarchical configurations for complex settings.
  4. Reloadable: You can configure your settings to reload automatically when they change.


Setting Up Configuration in ASP.NET 8

In this example, we’ll create a configuration for a DatabaseSettings class, which will contain a connection string and some other properties related to the database.


Step 1: Define the Configuration Class

First, create a class to hold the configuration settings. This class will map to the settings in your appsettings.json.



namespace MyApp.Models
 { 
    public class DatabaseSettings { 
        public string ConnectionString { get; set; } 
        public string Provider { get; set; } 
        public bool EnableLogging { get; set; } 
    } 
}

Here, we have a DatabaseSettings class with three properties: ConnectionString, Provider, and EnableLogging. These will be populated from the appsettings.json file.


Step 2: Add Configuration to appsettings.json

Now, add the configuration settings to the appsettings.json file. These values will be bound to the DatabaseSettings class.



{ 
    "DatabaseSettings": { 
        "ConnectionString": "Server=myserver;Database=mydb;User=myuser;Password=mypassword;", 
         "Provider": "SQLServer", "EnableLogging": true 
    } 
}


Here, we’ve defined the configuration for DatabaseSettings under the "DatabaseSettings" key in the appsettings.json file.


Step 3: Configure IOptions in the Program.cs

Now, in the Program.cs file, we’ll configure ASP.NET Core to read the settings from the appsettings.json file and bind them to our strongly-typed DatabaseSettings class using the IOptions pattern.



using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Hosting; 
using MyApp.Models; 

var builder = WebApplication.CreateBuilder(args); // Add services to the container.
 // Register DatabaseSettings for dependency injection 
builder.Services.Configure<DatabaseSettings>(builder.Configuration.GetSection("DatabaseSettings")); 
var app = builder.Build(); // Use the DatabaseSettings in a controller or a service 
app.MapGet("/", (IOptions<DatabaseSettings> options) => { 
    var dbSettings = options.Value; return Results.Json(dbSettings); 
}); 
app.Run();


In the above code:

  1. We use the Configure<T> method to bind the DatabaseSettings class to the configuration section "DatabaseSettings" from the appsettings.json file.
  2. We use the IOptions<DatabaseSettings> in the controller or endpoint to access the settings.


Step 4: Access Configuration in Controllers

You can also inject the IOptions<DatabaseSettings> into any service or controller to access these settings.



using Microsoft.AspNetCore.Mvc; 
using Microsoft.Extensions.Options; using MyApp.Models; 
namespace MyApp.Controllers { 

    [ApiController] 
    [Route("api/[controller]")]
    public class DatabaseController : ControllerBase { 
        private readonly DatabaseSettings _databaseSettings; 
        public DatabaseController(IOptions<DatabaseSettings> options) { 
            _databaseSettings = options.Value; 
        } 

        [HttpGet("get-settings")] 
        public IActionResult GetSettings() { 
            return Ok(_databaseSettings); 
        } 
    }
 }


Here, we’re injecting the IOptions<DatabaseSettings> into the controller and using the Value property to access the settings. The Value property contains the populated DatabaseSettings object with values from the appsettings.json file.


Here, we’re injecting the IOptions<DatabaseSettings> into the controller and using the Value property to access the settings. The Value property contains the populated DatabaseSettings object with values from the appsettings.json file.


Step 5: (Optional) Use IOptionsSnapshot for Scoped Lifetime

In certain scenarios, such as when you need to access updated configurations during the lifetime of a request, you can use IOptionsSnapshot instead of IOptions.



public class SomeService {

    private readonly IOptionsSnapshot<DatabaseSettings> _dbSettingsSnapshot; 
    public SomeService(IOptionsSnapshot<DatabaseSettings> dbSettingsSnapshot) { 
        _dbSettingsSnapshot = dbSettingsSnapshot; 
    } 

    public void PrintSettings() { 
        var settings = _dbSettingsSnapshot.Value; 
        Console.WriteLine($"Connection String: {settings.ConnectionString}"); 
    } 
}


  1. IOptionsSnapshot<T> provides access to configuration settings that are reloaded whenever the configuration changes. This is useful in scenarios where settings might change during the application’s lifetime, and you want to access the updated values.


Step 6: (Optional) Use IOptionsMonitor for Dynamic Updates

If you need to listen for changes in your configurations during the application’s lifecycle, you can use IOptionsMonitor. This is useful for settings that can be dynamically updated without restarting the application.



public class ConfigChangeListener { 

    private readonly IOptionsMonitor<DatabaseSettings> _optionsMonitor; 
    public ConfigChangeListener(IOptionsMonitor<DatabaseSettings> optionsMonitor) { 
        _optionsMonitor = optionsMonitor; 
        _optionsMonitor.OnChange(NotifyConfigChange); 
    } 
    private void NotifyConfigChange(DatabaseSettings newSettings) { 
        Console.WriteLine($"Configuration changed: {newSettings.ConnectionString}"); 
    } 
}

In the example above, the OnChange method is used to register a callback that gets triggered when the configuration values change.


Conclusion

In this post, we’ve demonstrated how to use the IOptions pattern in ASP.NET 8 to read and manage configuration settings. By using IOptions, IOptionsSnapshot, and IOptionsMonitor, you can easily access, monitor, and update your configuration in a type-safe and scalable way.


Key Benefits of IOptions:

  1. Type Safety: Ensures that configuration values are validated at compile-time rather than runtime.
  2. Separation of Concerns: Configuration settings are cleanly separated from your application logic.
  3. Ease of Access: Easily inject configuration settings into your services, controllers, and other parts of the application.

If you want to learn more about ASP.NET Core and modern web development, don’t forget to subscribe to my YouTube Channel and visit usmancode.com for more tutorials and resources!