Options Pattern in .NET Core with an Item API

DotNet Full Stack Dev
4 min readSep 22, 2024

--

The Options Pattern in .NET Core provides a flexible and organized way to manage configuration settings in your application. Instead of scattering configuration values throughout the codebase, the Options Pattern allows you to group related settings into classes, making them easier to maintain, validate, and test.

In this blog, we will dive into what the Options Pattern is, why it is beneficial, and how to implement it with an Item API example in .NET Core.

Embark on a journey of continuous learning and exploration with DotNet-FullStack-Dev. Uncover more by visiting our https://dotnet-fullstack-dev.blogspot.com reach out for further information.

What is the Options Pattern?

The Options Pattern is a way to represent and manage application settings in .NET Core by mapping configuration sections into strongly-typed classes. These options are typically loaded from configuration files such as appsettings.json but can also be loaded from other sources such as environment variables, user secrets, or even the Azure Key Vault.

Key Benefits of the Options Pattern:

  1. Type-Safety: Configuration values are mapped to a class, providing type safety, preventing hardcoding, and allowing better IntelliSense in IDEs.
  2. Centralized Configuration: Grouping related configuration values in a single place improves code readability and maintainability.
  3. Dependency Injection: The options are easily injectable into services or controllers, leveraging .NET Core’s built-in Dependency Injection (DI).

Configuring the Options Pattern with an Item API Example

Let’s walk through a scenario where we want to configure settings for an Item API. Assume that our API needs a few settings such as an API key, a base URL for accessing external resources, and a cache expiration time for items.

Step 1: Define the Configuration Class

First, we create a class that will represent the configuration options for our Item API. This class will hold properties for each setting we need.

public class ItemApiOptions
{
public string ApiKey { get; set; }
public string BaseUrl { get; set; }
public int CacheExpirationMinutes { get; set; }
}

Step 2: Add Configuration to appsettings.json

Next, we add the corresponding settings to the appsettings.json file. This file is the default configuration provider in a .NET Core application.

{
"ItemApi": {
"ApiKey": "your-api-key-here",
"BaseUrl": "https://api.example.com/items",
"CacheExpirationMinutes": 30
}
}

Step 3: Register the Configuration Class in the Startup

In the Startup.cs file (or Program.cs for .NET 6+), we need to bind the settings from appsettings.json to the ItemApiOptions class and register it in the dependency injection (DI) container.

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Bind the configuration section to the ItemApiOptions class
services.Configure<ItemApiOptions>(Configuration.GetSection("ItemApi"));

// Other service registrations
services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Usual middleware configuration
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
}
}

Step 4: Access the Options in the Item Controller

Now that we have registered the ItemApiOptions class, we can inject the options into the Item Controller using Dependency Injection. This allows us to access the settings from anywhere in the controller.

[ApiController]
[Route("api/[controller]")]
public class ItemController : ControllerBase
{
private readonly ItemApiOptions _itemApiOptions;

// Constructor Injection
public ItemController(IOptions<ItemApiOptions> itemApiOptions)
{
_itemApiOptions = itemApiOptions.Value;
}

[HttpGet]
public IActionResult GetItemSettings()
{
return Ok(new
{
ApiKey = _itemApiOptions.ApiKey,
BaseUrl = _itemApiOptions.BaseUrl,
CacheExpirationMinutes = _itemApiOptions.CacheExpirationMinutes
});
}
}

In the ItemController, we inject the IOptions<ItemApiOptions> and then access the configuration values via _itemApiOptions.

Step 5: Using the Configuration in Business Logic

Let’s imagine a service in the Item API that fetches items from an external API. We can inject the configuration options into this service and use them to build the request URL and manage caching.

public class ItemService : IItemService
{
private readonly HttpClient _httpClient;
private readonly ItemApiOptions _options;

public ItemService(HttpClient httpClient, IOptions<ItemApiOptions> options)
{
_httpClient = httpClient;
_options = options.Value;
}

public async Task<Item> GetItemByIdAsync(int id)
{
string requestUrl = $"{_options.BaseUrl}/{id}?apiKey={_options.ApiKey}";

HttpResponseMessage response = await _httpClient.GetAsync(requestUrl);
response.EnsureSuccessStatusCode();

var item = await response.Content.ReadAsAsync<Item>();

return item;
}
}

Here, the ItemService dynamically builds the request URL using the BaseUrl and ApiKey options from the ItemApiOptions configuration. This makes the service flexible and easily configurable without modifying code.

Step 6: Optional: Validating Options

.NET Core also supports options validation. You can validate options when they are configured to ensure that values are within an acceptable range or format.

services.AddOptions<ItemApiOptions>()
.Bind(Configuration.GetSection("ItemApi"))
.Validate(options => !string.IsNullOrEmpty(options.ApiKey), "API Key cannot be null or empty.")
.Validate(options => options.CacheExpirationMinutes > 0, "Cache expiration must be greater than 0.");

Advantages of Using the Options Pattern

  1. Separation of Concerns: Configuration settings are decoupled from the business logic, making the code easier to maintain.
  2. Centralized Management: All settings related to a specific area (e.g., the Item API) are grouped in one class, reducing scattered configuration throughout the code.
  3. Type-Safe Configuration: The strongly-typed approach ensures that mistakes like typo errors or incorrect types are caught at compile time.
  4. Ease of Testing: Since options are injected through DI, you can easily mock or change them during unit testing.

Conclusion

The Options Pattern in .NET Core provides a clean and structured way to manage configuration settings. In our Item API example, we demonstrated how to organize related settings into a class, bind them from appsettings.json, and inject them into a controller or service for use.

By leveraging the Options Pattern, you ensure that your application is flexible, maintainable, and scalable. The separation of configuration from business logic makes your code easier to manage as your application grows, and the strong typing helps catch errors early in development.

--

--

DotNet Full Stack Dev
DotNet Full Stack Dev

Written by DotNet Full Stack Dev

Join me to master .NET Full Stack Development & boost your skills by 1% daily with insights, examples, and techniques! https://dotnet-fullstack-dev.blogspot.com

No responses yet