IOptions<T> gives an ASP.NET Core service a strongly typed configuration object without making it read configuration keys itself. T is a plain C# class for the settings that service needs; the configured object is available through the interface’s Value property. section 10.3.1 section 10.5
To use it in a small application:
- Define a nonabstract options class with a public parameterless constructor and public properties for the values you want to bind. Nested complex properties are supported. section 10.3.1
- In Program.cs, call builder.Services.Configure<T>(builder.Configuration.GetSection("SectionName")) to register binding from a configuration section. The section name need not match the class name. section 10.3.1
- Request IOptions<T> through dependency injection and read its Value property. When the object is created, registered configuration actions set its properties; multiple Configure<T> calls can contribute to the result. section 10.3.1 section 31.2
Listing 10.8 Configuring the options classes using Configure<T> in Startup.cs
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MapSettings>(
builder.Configuration.GetSection("MapSettings")); #1
builder.Services.Configure<AppDisplaySettings>(
builder.Configuration.GetSection("AppDisplaySettings")); #2
The two registrations show the usual setup: each options class is bound to its own configuration section before the application uses it. section 10.3.1
IOptions<T> is registered as a singleton, so its Value stays the same even if underlying configuration changes. If an options object must be recreated for each request when configuration changes, use IOptionsSnapshot<T>; repeated binding has a performance cost. section 10.5
Binding is not the only way to configure options. Configure<T> can also take a lambda that sets properties in code. For configuration that needs another registered service, OptionsBuilder<T> supports a Configure<TDependency> call; an IConfigureOptions<T> class is another way to use dependency injection when configuring options. section 31.2 section 31.4
Listing 31.14 Using a DI service
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services
.AddOptions<CurrencyOptions>()
.BindConfiguration("Currencies")
.Configure<ICurrencyProvider>((opts, service) => #1
opts.Currencies = service.GetCurrencies()); #1
builder.Services.AddSingleton<ICurrencyProvider, CurrencyProvider>(); #2
WebApplication app = builder.Build();
app.MapGet("/", (IOptions<CurrencyOptions> opts) => opts.Value); #3
app.Run();
#1 Configures the Ioptions object using a service from DI
#2 Registers the service with the DI container
#3 Retrieves the IOptions object, which retrieves the service from DI and runs the lambda method
This example binds a configuration section, then uses a service from dependency injection to set an options property before an endpoint reads Value. section 31.2
If consumers only need T, you can instead bind and register T directly, or register T from IOptions<T>.Value. Direct injection avoids exposing IOptions<T> in a reusable library’s API, but these approaches give up options features such as reloading without further work. section 10.3.4
