How to Configure Options in ASP.NET — Digitteck
How to Configure Options in ASP.NET
dotnet·27 December 2022·4 min read

How to Configure Options in ASP.NET

Intro

An important part of any ASP.NET web application is how we handle our project settings, and a very strong emphasis should be placed on how to validate those settings. Think about what happens when you miss setting a proper int configuration value — would its default of 0 be acceptable?

Using Configure to Register an Option

Adding a configuration model in ASP.NET starts with a plain POCO and a call to Configure:

csharp
public class OptionMongoDb
{
    public string? Host { get; set; }
    public int Port { get; set; }
}
javascript
{
  "Mongo": {
    "Host": "localhost",
    "Port": 27017
  }
}
csharp
builder.Services
    .Configure<OptionMongoDb>(builder.Configuration.GetSection("Mongo"));

The option is now available everywhere via IOptions<OptionMongoDb>:

csharp
[ApiController]
[Route("api/options")]
public class OptionsController : ControllerBase
{
    private readonly IOptions<OptionMongoDb> _options;

    public OptionsController(IOptions<OptionMongoDb> options)
    {
        _options = options;
    }

    [HttpGet]
    public IActionResult Get()
    {
        return Ok();
    }
}

What's Behind the Configure Method

Decompiling Configure reveals that it calls AddOptions internally and registers an IConfigureOptions<TOption> service that binds the option model to the configuration section. This means you don't need to call services.AddOptions() yourself — it's called automatically, and the internal use of TryAdd ensures no duplicates.

csharp
public class OptionRedis
{
    public string? Host { get; set; }
    public int Port { get; set; }
}

public class OptionRedisConfigure : IConfigureOptions<OptionRedis>
{
    private readonly IConfiguration _configuration;

    public OptionRedisConfigure(IConfiguration configuration)
    {
        _configuration = configuration.GetSection("Redis");
    }

    public void Configure(OptionRedis options)
    {
        options.Host = _configuration.GetValue<string>("Host")
            ?? throw new Exception("The host value is not provided");
        options.Port = _configuration.GetValue<int?>("Port")
            ?? throw new Exception("The port value is not provided");
    }
}
csharp
builder.Services
    .AddSingleton<IConfigureOptions<OptionRedis>, OptionRedisConfigure>();

Using IConfigureOptions to Configure an Option

Since Configure just registers an IConfigureOptions<TOption> service under the hood, you can provide your own implementation — useful when configuration requires validation or transformation at bind time rather than relying on direct section binding.

Define the option model and implement IConfigureOptions:

csharp
public class OptionRedis
{
    public string? Host { get; set; }
    public int Port { get; set; }
}

public class OptionRedisConfigure : IConfigureOptions<OptionRedis>
{
    private readonly IConfiguration _configuration;

    public OptionRedisConfigure(IConfiguration configuration)
    {
        _configuration = configuration.GetSection("Redis");
    }

    public void Configure(OptionRedis options)
    {
        options.Host = _configuration.GetValue<string>("Host")
            ?? throw new Exception("The host value is not provided");
        options.Port = _configuration.GetValue<int?>("Port")
            ?? throw new Exception("The port value is not provided");
    }
}

Register the services — note the explicit AddOptions() call is required here since we're not using the Configure shorthand:

csharp
builder.Services
    .AddSingleton<IConfigureOptions<OptionRedis>, OptionRedisConfigure>();

Using IValidateOptions to Validate Option Values

With this method, validation is performed when a property on the option object is accessed — not when the object is configured.

Implement IValidateOptions<TOption> to add a dedicated validation service:

csharp
public class ValidateOptionsRedis : IValidateOptions<OptionRedis>
{
    public ValidateOptionsResult Validate(string name, OptionRedis options)
    {
        if (options.Host == "localhost")
        {
            return ValidateOptionsResult.Fail("Localhost is not a valid production host");
        }

        return ValidateOptionsResult.Success;
    }
}

Register both the configure and validate services:

csharp
builder.Services
    .AddSingleton<IConfigureOptions<OptionRedis>, OptionRedisConfigure>();
builder.Services
    .AddSingleton<IValidateOptions<OptionRedis>, ValidateOptionsRedis>();

Validate with Annotations

A cleaner alternative is to use data annotation attributes directly on the option model, and then use the AddOptions<> builder which exposes ValidateDataAnnotations and ValidateOnStart:

csharp
public class OptionsKafka
{
    [Required]
    [MinLength(1)]
    public string? Host { get; set; }
    public int Port { get; set; }
}
csharp
builder.Services.AddOptions<OptionsKafka>()
    .BindConfiguration("Kafka")
    .ValidateDataAnnotations()
    .ValidateOnStart();

"Annoyingly, there's no clean way to bind IValidateOptions to the OptionBuilder or make it run at startup. We have too many ways to describe the same thing — instead of focusing on business logic, we struggle understanding all these different styles."

Tags

.NETASP.NETC#Options
digitteck

© 2026 Digitteck