- Home
- .NET tutorials
- Validate .NET configuration on startup
Validate .NET configuration on startup
Published: Monday 13 April 2026
// in Program.cs
app.MapGet("/Product", () =>
new ProductDto(1, "Watch"));
We show you the correct way to organise Minimal API endpoints using separate endpoint classes → Learn more
You deploy your .NET app to production. It starts successfully. But invalid configuration values cause runtime exceptions.
Learn how to validate configuration on startup, so your app fails fast and never ships broken configuration again.
The option class
This is the options class that we will configure in the API.
// EmailOptions.cs
public class EmailOptions
{
public string SmtpHost { get; set; } = string.Empty;
public int SmtpPort { get; set; } = 21;
}// ConfigureServices.cs
public static class ConfigureServices
{
extension(IServiceCollection services)
{
public IServiceCollection AddConfigurationOptions()
{
services.AddOptions<EmailOptions>()
.BindConfiguration("Email");
return services;
}
}
}// Program.cs
builder.Services
.AddConfigurationOptions();Starting the application in production works fine. The problem appears when running the endpoints.
// IEmailService.cs
public interface IEmailService
{
void SendEmail();
}// EmailService.cs
public class EmailService : IEmailService
{
private readonly EmailOptions _emailOptions;
public EmailService(IOptionsSnapshot<EmailOptions> emailOptions)
{
_emailOptions = emailOptions.Value;
}
public void SendEmail()
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(_emailOptions.SmtpHost))
{
errors.Add("'SmtpHost' is not provided");
}
if (errors.Any())
{
throw new NullReferenceException(
"Unable to send email due to invalid configuration. " +
"Missing the following configuration values:" +
$"\r\n- {string.Join("\r\n", errors)}");
}
// Send email
}
}// EmailsEndpoints.cs
public static class EmailsEndpoints
{
extension(WebApplication app)
{
public WebApplication MapEmailsEndpoints()
{
var group = app.MapGroup("/api/emails");
group.MapPost("/send", SendEmail);
return app;
}
}
public static NoContent SendEmail(IEmailService emailService)
{
emailService.SendEmail();
return TypedResults.NoContent();
}
}// Program.cs
app.MapEmailsEndpoints();When the SendEmail endpoint handler runs, it calls SendEmail in EmailService. If SmtpHost is empty, it throws a NullReferenceException.
And that is where the problem lies.
You can deploy the application to production. It starts successfully and you assume everything is working. Until an endpoint is called and exceptions start being thrown.
Surely there must be a way to validate configuration on startup?
Add data annotations
One option is to add data annotations to the properties in your options classes. In this example, we mark SmtpHost as [Required].
// EmailOptions.cs
public class EmailOptions
{
[Required]
public string Host { get; set; } = string.Empty;
public int Port { get; set; } = 21;
}However, we also need to add extra configuration when registering the options classes. This is done by calling AddOptionsWithValidateOnStart and ValidateDataAnnotations.
// ConfigureServices.cs
public IServiceCollection AddConfigurationOptions()
{
services.AddOptionsWithValidateOnStart<EmailOptions>()
.BindConfiguration("Email")
.ValidateDataAnnotations();
return services;
}Now, when the application starts, it throws an exception if the configuration is missing or invalid, and the app crashes.
fail: Microsoft.Extensions.Hosting.Internal.Host[11]
Hosting failed to start
Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for 'EmailOptions' members: 'SmtpHost' with the error: 'The SmtpHost field is required.'.If you are new to validating with data annotations, we cover this in our Minimal APIs for complete beginners course, where you will learn how to validate API requests using this approach.
FluentValidation
Data annotations are one option, but you can also use FluentValidation. This requires additional setup but is much easier to test.
Install NuGet packages
Install the following packages:
Create validator classes
First, create an AbstractOptionsValidator class. This inherits from AbstractValidator (from FluentValidation) and implements IValidateOptions so the options can be validated on startup.
// AbstractOptionsValidator.cs
public abstract class AbstractOptionsValidator<TOptions> :
AbstractValidator<TOptions>,
IValidateOptions<TOptions>
where TOptions : class
{
public ValidateOptionsResult Validate(string? name, TOptions options)
{
var result = this.Validate(options);
if (!result.IsValid)
{
return ValidateOptionsResult.Fail(
result.Errors.Select(e =>
$"{options.GetType().Name}: {e.PropertyName} - {e.ErrorMessage}"));
}
return ValidateOptionsResult.Success;
}
}Next, create a validator for the options class by inheriting from AbstractOptionsValidator.
// EmailOptionsValidator.cs
public class EmailOptionsValidator : AbstractOptionsValidator<EmailOptions>
{
public EmailOptionsValidator()
{
RuleFor(e => e.SmtpHost)
.NotEmpty();
}
}Register the validator class
Register the options validator as a singleton.
// ConfigureServices.cs
public static class ConfigureServices
{
extension(IServiceCollection services)
{
...
public IServiceCollection AddOptionsValidators()
{
services.AddSingleton<IValidateOptions<EmailOptions>, EmailOptionsValidator>();
return services;
}
}
}// Program.cs
builder.Services
.AddOptionsValidators();If you run the application now, it will still start even when the configuration is missing. This is because we have not yet enabled validation on startup.
To fix this, add ValidateOnStart when registering the options.
// ConfigureServices.cs
public IServiceCollection AddConfigurationOptions()
{
services.AddOptions<EmailOptions>()
.BindConfiguration("Email")
.ValidateOnStart();
return services;
}Now, when the application starts and the configuration is invalid, the validation error is shown immediately and the app crashes.
fail: Microsoft.Extensions.Hosting.Internal.Host[11]
Hosting failed to start
Microsoft.Extensions.Options.OptionsValidationException: EmailOptions: SmtpHost -'Smtp Host' must not be empty.Watch the video
Watch the video where we walk through how to set up and configure configuration validation on startup using both data annotations and FluentValidation.
Download the code example
If you want to try out this tutorial, you can download the code example which provides an example using data annotations and FluentValidation.
Related pages