Skip to content

Repository files navigation

DotnetStarsDiscordworkflownugetnugetIssues OpenForksLicenseTwitter

TwitterTwitter

TimeWarp.OptionsValidation

TimeWarp Logo

TimeWarp.OptionsValidation integrates FluentValidation with Microsoft.Extensions.Options to provide automatic validation of your configuration settings at application startup.

Why Use This Library?

Configuration errors are a common source of runtime failures. TimeWarp.OptionsValidation helps you fail fast by validating all configuration settings when your application starts, rather than discovering errors when the configuration is first accessed (which could be hours or days later in production).

Key Benefits:

  • Validates configuration settings using FluentValidation rules
  • Integrates seamlessly with Microsoft.Extensions.Options
  • Catches configuration errors at startup, not at runtime
  • Provides clear, actionable error messages
  • Supports both IConfiguration binding and programmatic configuration

Give a Star! ⭐

If you like or are using this project please give it a star. Thank you!

Installation

dotnet add package TimeWarp.OptionsValidation

You can see the latest NuGet packages from the official TimeWarp NuGet page.

Usage

Basic Setup with Automatic Startup Validation

Use AddFluentValidatedOptions() which returns OptionsBuilder<T>, allowing you to chain with .ValidateOnStart() for automatic startup validation.

1. Define Your Options Class with Nested Validator

usingFluentValidation;publicclassDatabaseOptions{publicstringConnectionString{get;set;}=string.Empty;publicintMaxRetries{get;set;}publicintCommandTimeout{get;set;}// Nested validator - sealed and only used herepublicsealedclassValidator:AbstractValidator<DatabaseOptions>{publicValidator(){RuleFor(x =>x.ConnectionString).NotEmpty().WithMessage("Database connection string is required");RuleFor(x =>x.MaxRetries).GreaterThan(0).LessThanOrEqualTo(10).WithMessage("MaxRetries must be between 1 and 10");RuleFor(x =>x.CommandTimeout).GreaterThanOrEqualTo(30).WithMessage("CommandTimeout must be at least 30 seconds");}}}

2. Register with Automatic Startup Validation

usingMicrosoft.Extensions.DependencyInjection;varbuilder=WebApplication.CreateBuilder(args);// Register options with automatic startup validationbuilder.Services.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(builder.Configuration).ValidateOnStart();// ✅ Validates when host starts, throws on errorvarapp=builder.Build();app.Run();// Validation happens automatically before this runs

What this does:

  • Binds the DatabaseOptions section from appsettings.json
  • Registers the FluentValidation validator
  • Validates configuration at startup (before app.Run())
  • Fails fast with clear error messages if configuration is invalid
  • No manual validation calls needed!

Configuration Binding

The library automatically discovers which configuration section to bind based on simple, predictable rules.

Default: Class Name

By default, the library uses the class name as the configuration section name:

publicclassDatabaseOptions{publicstringConnectionString{get;set;}=string.Empty;// ...}

Binds to "DatabaseOptions" section:

{
"DatabaseOptions": {
"ConnectionString": "Server=localhost;Database=myapp;",
"MaxRetries": 3,
"CommandTimeout": 30
}
}
// Automatically binds to "DatabaseOptions" sectionservices.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(configuration).ValidateOnStart();

Custom Configuration Key with [ConfigurationKey] Attribute

Override the default by decorating your options class with [ConfigurationKey]:

Simple Configuration Key:

usingTimeWarp.OptionsValidation;[ConfigurationKey("Database")]publicclassDatabaseOptions{publicstringConnectionString{get;set;}=string.Empty;// ...}

Binds to "Database" section:

{
"Database": {
"ConnectionString": "Server=localhost;Database=myapp;",
"MaxRetries": 3,
"CommandTimeout": 30
}
}

Hierarchical Key with Colon Separator:

[ConfigurationKey("MyApp:Settings:Database")]publicclassDatabaseOptions{publicstringConnectionString{get;set;}=string.Empty;// ...}

Binds to nested "MyApp" → "Settings" → "Database" path:

{
"MyApp": {
"Settings": {
"Database": {
"ConnectionString": "Server=localhost;Database=myapp;",
"MaxRetries": 3,
"CommandTimeout": 30
}
}
}
}
// Automatically binds to configuration key specified in attributeservices.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(configuration).ValidateOnStart();

Advanced: Manual Section Binding

For dynamic section paths or complex scenarios not covered by the attribute:

// Manual binding for runtime-determined pathsstringenvironment=builder.Environment.EnvironmentName;services.AddOptions<DatabaseOptions>().Bind(configuration.GetSection($"{environment}:Database")).ValidateFluentValidation<DatabaseOptions,DatabaseOptions.Validator>().ValidateOnStart();

Automatic Configuration Key Resolution Summary:

  • ✅ Uses class name: DatabaseOptions"DatabaseOptions"
  • ✅ Simple override: [ConfigurationKey("Database")]"Database"
  • ✅ Hierarchical paths: [ConfigurationKey("MyApp:Settings:Database")]"MyApp" → "Settings" → "Database"
  • ❌ Does NOT trim suffixes like "Options" automatically
  • ❌ Does NOT pluralize names automatically

Programmatic Configuration

You can also configure options programmatically without IConfiguration:

services.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(options =>{options.ConnectionString="Server=localhost;Database=myapp;";options.MaxRetries=3;options.CommandTimeout=30;}).ValidateOnStart();

Complete Startup Example

usingMicrosoft.Extensions.DependencyInjection;varbuilder=WebApplication.CreateBuilder(args);// Register multiple validated options with automatic startup validationbuilder.Services.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(builder.Configuration).ValidateOnStart();builder.Services.AddFluentValidatedOptions<CacheOptions,CacheOptions.Validator>(builder.Configuration).ValidateOnStart();builder.Services.AddFluentValidatedOptions<EmailOptions,EmailOptions.Validator>(builder.Configuration).ValidateOnStart();varapp=builder.Build();app.Run();// All options validated before this runs

If any configuration is invalid, the application will fail to start with clear error messages indicating exactly which settings are invalid and why.

Without Startup Validation

If you don't need automatic startup validation, simply omit .ValidateOnStart():

// Validates on first access instead of at startupservices.AddFluentValidatedOptions<DatabaseOptions,DatabaseOptions.Validator>(configuration);// No .ValidateOnStart() call - validation happens lazily

This approach validates options when they're first accessed rather than at application startup.

Features

  • Automatic Startup Validation: Use .ValidateOnStart() to fail fast on invalid configuration
  • Automatic Key Discovery: Uses the class name as the configuration key by default
  • Custom Key Mapping: Use [ConfigurationKey] attribute to override the configuration key
  • Hierarchical Keys: Support for nested configuration paths using colon separators
  • Seamless Integration: Works with Microsoft.Extensions.Options infrastructure and OptionsBuilder<T>
  • FluentValidation Power: Rich validation rules, custom validators, conditional validation
  • Clear Error Messages: Detailed, actionable error messages from FluentValidation
  • Type Safety: Strongly-typed options with compile-time checking
  • Flexible API: Choose between fluent API (with .ValidateOnStart()) or simple registration

Releases

See the Release Notes

Unlicense

License

Contributing

Time is of the essence. Before developing a Pull Request I recommend opening a discussion.

Please feel free to make suggestions and help out with the documentation. Please refer to Markdown for how to write markdown files.

Contact

Sometimes the github notifications get lost in the shuffle. If you file an issue and don't get a response in a timely manner feel free to ping on our Discord server.

Discord

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages