The Microsoft.Extensions.Options.OptionsValidationException
with the message “Configuration options validation failed” occurs in .NET applications when the validation of configuration options fails. This typically happens when using the IOptions<T>
, IOptionsSnapshot<T>
, or IOptionsMonitor<T>
pattern in ASP.NET Core to bind and validate configuration settings.
Here’s a detailed explanation of the issue and how to resolve it:
Common Causes
- Missing Required Configuration Values
- A required configuration value is missing from the configuration source (e.g.,
appsettings.json
, environment variables).
- Invalid Configuration Values
- A configuration value does not meet the validation rules (e.g., a string is too short, a number is out of range).
- Validation Rules Not Met
- The validation rules defined for the options class are not satisfied.
- Configuration Binding Issues
- The configuration section is not correctly bound to the options class.
- Incorrect Configuration Structure
- The structure of the configuration file does not match the expected structure for the options class.
Solutions
1. Check Configuration Values
- Ensure all required configuration values are present in the configuration source (e.g.,
appsettings.json
). Exampleappsettings.json
:
{
"MySettings": {
"ApiKey": "your-api-key",
"Timeout": 30
}
}
2. Define Validation Rules
- Use data annotations or custom validation logic to define validation rules for the options class. Example with Data Annotations:
public class MySettings
{
[Required]
public string ApiKey { get; set; }
[Range(1, 60)]
public int Timeout { get; set; }
}
3. Register and Validate Options
- Register the options class and enable validation in the
ConfigureServices
method. Example inProgram.cs
(ASP.NET Core 6+):
var builder = WebApplication.CreateBuilder(args);
// Bind and validate configuration
builder.Services.AddOptions<MySettings>()
.Bind(builder.Configuration.GetSection("MySettings"))
.ValidateDataAnnotations()
.Validate(settings => settings.Timeout > 0, "Timeout must be greater than 0.");
var app = builder.Build();
Example in Startup.cs
(ASP.NET Core 5 or earlier):
public void ConfigureServices(IServiceCollection services)
{
// Bind and validate configuration
services.AddOptions<MySettings>()
.Bind(Configuration.GetSection("MySettings"))
.ValidateDataAnnotations()
.Validate(settings => settings.Timeout > 0, "Timeout must be greater than 0.");
}
4. Handle Validation Errors Gracefully
- Catch the
OptionsValidationException
and log or handle it appropriately. Example:
try
{
var mySettings = app.Services.GetRequiredService<IOptions<MySettings>>().Value;
}
catch (OptionsValidationException ex)
{
Console.WriteLine($"Configuration validation failed: {ex.Message}");
// Log or handle the exception
}
5. Check Configuration Binding
- Ensure the configuration section name matches the section being bound. Example:
// Correct binding
builder.Services.AddOptions<MySettings>()
.Bind(builder.Configuration.GetSection("MySettings"));
6. Use Custom Validators
- For complex validation logic, implement a custom validator by implementing the
IValidateOptions<T>
interface. Example:
public class MySettingsValidator : IValidateOptions<MySettings>
{
public ValidateOptionsResult Validate(string name, MySettings options)
{
if (string.IsNullOrEmpty(options.ApiKey))
{
return ValidateOptionsResult.Fail("ApiKey is required.");
}
return ValidateOptionsResult.Success;
}
}
// Register the custom validator
builder.Services.AddSingleton<IValidateOptions<MySettings>, MySettingsValidator>();
Debugging Tips
- Use logging to inspect the configuration values being loaded.
- Verify the structure of the configuration file matches the options class.
- Check the exception details for specific validation errors.
Best Practices
- Always validate configuration options to ensure the application starts with valid settings.
- Use meaningful error messages in validation rules to make debugging easier.
- Avoid hardcoding configuration values; always use the configuration system.
- Regularly review and update configuration files to ensure they meet the application’s requirements.
Example of a Complete Setup
Options Class
public class MySettings
{
[Required]
public string ApiKey { get; set; }
[Range(1, 60)]
public int Timeout { get; set; }
}
Configuration File (appsettings.json
)
{
"MySettings": {
"ApiKey": "your-api-key",
"Timeout": 30
}
}
Service Registration and Validation
var builder = WebApplication.CreateBuilder(args);
// Bind and validate configuration
builder.Services.AddOptions<MySettings>()
.Bind(builder.Configuration.GetSection("MySettings"))
.ValidateDataAnnotations()
.Validate(settings => settings.Timeout > 0, "Timeout must be greater than 0.");
var app = builder.Build();
Using the Options
app.MapGet("/", (IOptions<MySettings> mySettings) =>
{
return Results.Ok(mySettings.Value);
});