How To Use The Options Pattern In ASP.NET Core 7
Tags: aspnet, aspnetcore, dotnet, csharp
Published: 2023-09-16 10:48:55

---
title: How To Use The Options Pattern In ASP.NET Core 7
published: true
date: 2022-11-19 00:00:00 UTC
tags: aspnet,aspnetcore,dotnet,csharp
canonical_url: https://www.milanjovanovic.tech/blog/how-to-use-the-options-pattern-in-asp-net-core-7
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k627uay1da39m99v69me.png
---
In this week's newsletter I want to show you how you can use the powerful **options pattern** in **ASP.NET Core 7**.

The **options pattern** uses classes to provide **strongly typed settings** in your application at runtime.

The values for the **options** instance can come from multiple sources. The typical use case is to provide the settings from application configuration.

You can configure the **options pattern** in a few different ways in **ASP.NET Core**. I want to discuss some of the approaches and their potential benefits.

## Creating The Options Class

I want to set the stage first, by creating the **options** class and explaining what settings we want to bind to it.

We want to configure JWT Authentication for our application, so we decided to create the `JwtOptions` class to hold that configuration:

```csharp
public class JwtOptions
{
    public string Issuer { get; init; }
    public string Audience { get; init; }
    public string SecretKey { get; init; }
}
```

And let's imagine that inside of our `appsettings.json` file we have the following configuration values:

```csharp
"Jwt": {
    "Issuer": "Gatherly",
    "Audience": "Gatherly",
    "SecretKey": "dont-tell-anyone!"
}
```

Alright, that's looking good. Now I want to show you a few ways to bind the values from JSON to our `JwtOptions` class.

## Setting Up Options Pattern Using IConfiguration
The most straightforward approach is to use the `IConfiguration` instance that we can access while registering services.

We need to call the `IServiceCollection.Configure<TOptions>` method, and specify the `JwtOptions` as the generic argument:

```csharp
builder.Services.Configure<JwtOptions>(
    builder.Configuration.GetSection("Jwt"));
```

It doesn't get simpler than this, does it?

The only downside is that we are limited to the configuration values provided through application configuration.

This can be extended to include environment variables and user secrets also.

## Setting Up Options Pattern Using IConfigureOptions

If you want a more robust approach, I have you covered. We're going to use the `IConfigureOptions` interface to define a class to configure our **strongly typed options**.

There are two steps that we need to follow in this case:

- Create the `IConfigureOptions` implementation
- Call `IServiceCollection.ConfigureOptions<TOptions>` with our `IConfigureOptions`implementation as the generic argument

To start off, we will create the `JwtOptionsSetup` class:

```csharp
public class JwtOptionsSetup : IConfigureOptions<JwtOptions>
{
    private const string SectionName = "Jwt";
    private readonly IConfiguration _configuration;

    public JwtOptionsSetup(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Configure(JwtOptions options)
    {
        _configuration
            .GetSection(SectionName)
            .Bind(options);
    }
}
```

We wrote more code, to achieve the same thing. Was it worth it?

Perhaps, if you consider that we now have access to **dependency injection** in the `JwtOptionsSetup` class. This means that we can resolve other services that we can use to get the configuration values.

We also need to tell the application to use the `JwtOptionsSetup` class:

```csharp
builder.Services.ConfigureOptions<JwtOptionsSetup>();
```

When we try to inject our `JwtOptions` somewhere, the `JwtOptionsSetup.Configure`method will be called first the calculate the correct values.

## Injecting Options With IOptions

We've seen a few examples for how to configure the **options pattern** with the `JwtOptions` class.

But how do we actually use the **options pattern**?

Easy, you just need to inject `IOptions<JwtOptions>` from the constructor.

I'll just show the `JwtProvider` constructor here, for brevity.

```csharp
public JwtProvider(IOptions<JwtOptions> options)
{
    _options = options.Value;
}
```

The actual `JwtOptions` instance is available on the `IOptions<JwtOptions>.Value` property.

The `IOptions` instance that we injected here is configured as a **Singleton** in dependency injection. This is very important to be aware of.

## What About IOptionsSnapshot and IOptionsMonitor?

If you want to use the latest configuration values every time you inject an **options** class, then injecting `IOptions` won't work.

However, you can use the `IOptionsSnapshot` interface instead:

- It provides the latest configuration snapshot (cached per request)
- It is registered as a **Scoped** service
- It detects configuration changes after application start

You can also use the `IOptionsMonitor` which retrieves the current option values at any time, and it's a **Singleton** service.

## Wrapping up

The **options pattern** gives us a way to use strongly typed configuration classes in our application.

We can configure the options class in a simple way with `IConfiguration`, or we can create an `IConfigureOptions` implementation if we need something more powerful.

When it comes to using the **options pattern** , we have three approaches:

- [`IOptions`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptions-1?view=dotnet-plat-ext-7.0)
- [`IOptionsSnapshot`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptionssnapshot-1?view=dotnet-plat-ext-7.0)
- [`IOptionsMonitor`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptionsmonitor-1?view=dotnet-plat-ext-7.0)

Deciding which of them to use in your application depends on what kind of behavior you want. If you don't need to support refreshing configuration values after application start, `IOptions` is a perfect solution.

* * *

**P.S. Whenever you're ready, there are 2 ways I can help you:**

1. [**Pragmatic Clean Architecture:**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting) This comprehensive course will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture. [**Join 950+ students here.**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting)

2. [**Patreon Community:**](https://www.patreon.com/milanjovanovic) Think like a senior software engineer with **access to the source code** I use in my YouTube videos and **exclusive discounts** for my courses. [**Join 820+ engineers here.**](https://www.patreon.com/milanjovanovic)