The options pattern is an indirect way to dependency inject settings into a registered service. If you’re using code that implements the options pattern, then you’re required to supply an IOptions<T> object.
For example, let’s say you’re using the MovieService class and it has the following constructor:
public MovieService(IOptions<MovieSettings> options)
Code language: C# (cs)
This requires you to supply the IOptions<MovieSettings> parameter.
If the settings are in appsettings.json, you can use AddOptions().Bind():
public class Startup
{
//rest of the class
public void ConfigureServices(IServiceCollection services)
{
//rest of method
services.AddOptions<MovieSettings>().Bind(Configuration.GetSection("MovieSettings"));
}
}
Code language: C# (cs)
What if you want to supply hardcoded values, or if you want to fetch the settings from somewhere using a registered service (such as a database repository class)? In this article, I’ll show how to supply the IOptions<T> object in these scenarios.
Table of Contents
Supply IOptions<T> with hardcoded values
When you’re using code that implements the options pattern, and you want to use hardcoded values, then you can register the Options<T> object and use Options.Create().
For example, let’s say you want to hardcode the MovieSettings values. Here’s how to supply IOptions<MovieSettings> with hardcoded values:
using Microsoft.Extensions.Options;
public class Startup
{
//rest of the class
public void ConfigureServices(IServiceCollection services)
{
//rest of method
services.AddSingleton<IOptions<MovieSettings>>(_ =>
{
return Options.Create(new MovieSettings()
{
MovieAPIUrl = "https://localhost:12345/movies/api"
});
});
}
}
Code language: C# (cs)
Supply IOptions<T> from a registered service
Let’s say you want to supply IOptions<MovieSettings> by querying the database using the registered MovieSettingsRepository service.
There are two approaches for doing that:
- Use AddOptions<MovieSettings>().Configure<IMovieSettingsRepository>().
- Register IOptions<MovieSettings> directly, allowing you to use Options.Create().
I’ll show both approaches below.
Approach 1 – Use AddOptions<MovieSettings>().Configure<IMovieSettingsRepository>()
With this overload of AddOptions().Configure(), you define a lambda that accepts the MovieSettings object and the resolved IMovieSettingsRepository instance. You can set properties on the MovieSettings object.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMovieSettingsRepository, MovieSettingsRepository>();
services.AddOptions<MovieSettings>()
.Configure<IMovieSettingsRepository>((movieSettings, movieSettingsRepo) =>
{
movieSettings.MovieAPIUrl = movieSettingsRepo.GetSettings().MovieAPIUrl;
});
}
}
Code language: C# (cs)
This approach is good if you only want to set a few of the properties.
Approach 2 – Register IOptions<MovieSettings> directly, allowing you to use Options.Create()
You don’t need to use AddOptions(). You can register IOptions<MovieSettings> directly just like anything else. With this approach, you can resolve the IMovieSettingsRepository instance and use it to create the MovieSettings object and pass it to Options.Create().
using Microsoft.Extensions.Options;
public class Startup
{
//rest of class
public void ConfigureServices(IServiceCollection services)
{
//rest of method
services.AddSingleton<IMovieSettingsRepository, MovieSettingsRepository>();
services.AddSingleton<IOptions<MovieSettings>>(serviceProvider =>
{
var repo = serviceProvider.GetService<IMovieSettingsRepository>();
return Options.Create(repo.GetSettings());
});
}
}
Code language: C# (cs)
This approach gives you full control over how the IOptions<MovieSettings> object is supplied.