C# – How to supply IOptions

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.

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 fetching MovieSettings from 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.

Leave a Comment