Skip to content

[API Proposal]: Add extensions to create an OptionsBuilder with ValidateOnStart support #89263

@steveharter

Description

@steveharter

Background and motivation

Based on cloud native scenarios, these extensions methods were used and they make sense to add to the System.Microsoft.Extensions.Options.library.

Note that in cloud native, these methods were called "AddValidatedOptions"; here they are called "AddValidateOnStartOptions".

API Proposal

namespace namespace Microsoft.Extensions.DependencyInjection;

public static partial class OptionsServiceCollectionExtensions
{
    // Calls ValidateOnStart()
+   public static OptionsBuilder<TOptions> AddValidateOnStartOptions
+       <[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>
+        (this IServiceCollection services,
+        string? name = null)
+        where TOptions : class
    {
        // Simple wrapper like this:
        return new OptionsBuilder<TOptions>(services, name ?? Options.DefaultName).ValidateOnStart();
    }

    // Supports IValidateOptions and call ValidateOnStart() above
+   public static OptionsBuilder<TOptions> AddValidateOnStartOptions<
+       [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions,
+       [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TValidateOptions>(
+       this IServiceCollection services,
+       string? name = null)
+       where TOptions : class
+       where TValidateOptions : class, IValidateOptions<TOptions>
      {
         // Simple wrapper like this:
         services.AddOptions().TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions<TOptions>, TValidateOptions>());
         return new OptionsBuilder<TOptions>(services, name ?? Options.DefaultName).ValidateOnStart();
      }

API Usage

// Before:
IHostBuilder builder = ...
builder.services
    .AddOptions<MyOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .Validate(o => o.MySetting == true)
    .ValidateOnStart();
// After:
IHostBuilder builder = ...
builder.Services
    .AddValidateOnStartOptions<MyOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .Validate(o => o.MySetting == true);

// Before:
IHostBuilder builder = ...
builder.Services
    .AddOptions<MyOptions>()
    .AddSingleton<IValidateOptions<MyOptions>>(new MyOptionsValidator(builder .Name)) // or TryAddEnumerable
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .ValidateOnStart();
// After:
IHostBuilder builder = ...
builder.Services.
    .AddValidateOnStartOptions<MyOptions, MyOptionsValidator>(builder.Name))
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))

Alternative Designs

No response

Risks

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions