How to supply IOptions in ASP.NET Core

By FoxLearn 2/4/2025 8:48:54 AM   10
The options pattern in C# allows you to inject settings into a registered service through dependency injection. If your code uses this pattern, you will need to provide an IOptions<T> object.

Using IOptions with EmailSettings

Let’s say you have an EmailService class that requires IOptions<EmailSettings> in its constructor:

public class EmailService
{
    private readonly EmailSettings _emailSettings;

    public EmailService(IOptions<EmailSettings> options)
    {
        _emailSettings = options.Value;
    }
}

This requires you to supply an IOptions<EmailSettings> object. If the settings are stored in appsettings.json, you can use AddOptions() with Bind() to bind the settings:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions<EmailSettings>().Bind(Configuration.GetSection("EmailSettings"));
    }
}

But what if you want to supply the settings with hardcoded values, or fetch them from a database using a registered service? This article will show you how to handle those scenarios.

Supply IOptions<T> with Hardcoded Values

When you want to use hardcoded values for the settings, you can register the Options<T> object using Options.Create().

For example, let’s assume you want to hardcode EmailSettings like this:

using Microsoft.Extensions.Options;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IOptions<EmailSettings>>(_ =>
        {
            return Options.Create(new EmailSettings()
            {
                SmtpServer = "smtp.example.com",
                Port = 587,
                UseSsl = true
            });
        });
    }
}

Supply IOptions<T> from a Registered Service

Let’s assume now you want to supply IOptions<EmailSettings> by fetching the settings from a database through a registered service called EmailSettingsRepository.

Use AddOptions<EmailSettings>().Configure<IEmailSettingsRepository>()

This method allows you to use a lambda that accepts the EmailSettings object and the resolved IEmailSettingsRepository service, so you can configure the EmailSettings object based on data from the repository.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IEmailSettingsRepository, EmailSettingsRepository>();

        services.AddOptions<EmailSettings>()
            .Configure<IEmailSettingsRepository>((emailSettings, emailSettingsRepo) =>
            {
                var settings = emailSettingsRepo.GetSettings();
                emailSettings.SmtpServer = settings.SmtpServer;
                emailSettings.Port = settings.Port;
                emailSettings.UseSsl = settings.UseSsl;
            });
    }
}

Register IOptions<EmailSettings> Directly with Options.Create()

If you need more flexibility, you can register the IOptions<EmailSettings> directly and resolve the IEmailSettingsRepository instance in the lambda. Then, use Options.Create() to pass the settings.

using Microsoft.Extensions.Options;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IEmailSettingsRepository, EmailSettingsRepository>();

        services.AddSingleton<IOptions<EmailSettings>>(serviceProvider =>
        {
            var repo = serviceProvider.GetService<IEmailSettingsRepository>();
            return Options.Create(repo.GetSettings());
        });
    }
}

With these methods, you can supply IOptions<T> in different ways, whether it’s from hardcoded values or a service like a database repository. You can adapt the solution based on your application's requirements.