IStartupFilter in ASP.NET Core validates settings when app launches

1 minute read

Background

ASP.NET Core has a function to verify the data read from the settings such as appsettings.json.

ASP.NET Core Option Patterns: Option Validation (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1#options-validation)

It is very convenient to implement verification easily by using the above function, but there were times when the verification timing was the timing when it was taken out from the DI container and it was delayed to notice the setting error. ..

I want to notice the setting error as soon as possible, so I tried the implementation that verifies the setting at startup by referring to the implementation example of Github Issue here. So, I will leave an example of implementation and usage as a memorandum.

environment

ASP.NET Core 3.1

Implementation

Define a StartupFilter that validates the settings.

public class StartupOptionsValidationFilter<T> : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            var options = builder.ApplicationServices.GetService(typeof(IOptions<>).MakeGenericType(typeof(T)));
            if (options != null)
                _ = ((IOptions<object>)options).Value;

            next(builder);
        };
    }
}

Defines an extension method that registers the above StartupFilter in the DI.

public static class OptionsBuilderValidationExtensions
{
    public static OptionsBuilder<TOptions>  <TOptions>(this OptionsBuilder<TOptions> optionsBuilder)
        where TOptions : class
    {
        optionsBuilder.Services.AddTransient<IStartupFilter, StartupOptionsValidation<TOptions>>();
        return optionsBuilder;
    }
}

Usage example

Prepare a class to bind the configuration file.
This time, we have prepared validation by DataAnnotations and custom validation rule ʻIsValid ()`.

public class SettingA
{
    [Required]
    public string OptionA { get; set; }
    public bool UseOptionB { get; set; }
    public string OptionB { get; set; }

    public bool IsValid()
    {
        //OptionB must be set if UseOptionB is true
        return !(UseOptionB && OptionB == null);
    }
}

Add the configuration file to the DI with the ConfigureServices method in Startup.cs as follows:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions<SettingA>()
        .Configure(option => Configuration.Bind("settingA", option))
        .ValidateDataAnnotations() //Verification by DataAnnotations
        .Validate(option => option.IsValid()) //Custom validation rules"IsValid()"Verification by
        .ValidateEagerly(); //Added StartupFilter to DI to validate settings at startup

    services.AddControllers();
}