Using options pattern in a different way
amirhessampourhossein opened this issue ยท 4 comments
amirhessampourhossein commented
Currently, this is how your JwtSettings
is configured ๐
var jwtSettings = new JwtSettings();
configuration.Bind(JwtSettings.Section, jwtSettings);
services.AddSingleton(Options.Create(jwtSettings));
What's your opinion about the approach below ๐
services.AddOptions<JwtSettings>().BindConfiguration(JwtSettings.Section);
we could also add validation in two different ways :
- Data Annotations (built-in)
services.AddOptions<JwtSettings>()
.BindConfiguration(JwtSettings.Section)
.ValidateDataAnnotations()
.ValidateOnStart();
- Fluent Validation
public class FluentValidateOptions<TOptions>
: IValidateOptions<TOptions>
where TOptions : class
{
private readonly IServiceProvider _serviceProvider;
private readonly string? _name;
public FluentValidateOptions(IServiceProvider serviceProvider, string? name)
{
_serviceProvider = serviceProvider;
_name = name;
}
public ValidateOptionsResult Validate(string? name, TOptions options)
{
if (_name is not null && _name != name)
return ValidateOptionsResult.Skip;
ArgumentNullException.ThrowIfNull(options);
using var scope = _serviceProvider.CreateScope();
var validator = scope.ServiceProvider.GetRequiredService<IValidator<TOptions>>();
var result = validator.Validate(options);
if (result.IsValid)
return ValidateOptionsResult.Success;
var errors = result.Errors
.Select(x => $"Validation failed for {x.PropertyName} with the error: {x.ErrorMessage}")
.ToList();
return ValidateOptionsResult.Fail(errors);
}
public static OptionsBuilder<TOptions> ValidateFluentValidation<TOptions>(
this OptionsBuilder<TOptions> optionsBuilder)
where TOptions : class
{
optionsBuilder.Services.AddSingleton<IValidateOptions<TOptions>>(
serviceProvider => new FluentValidateOptions<TOptions>(
serviceProvider,
optionsBuilder.Name
));
return optionsBuilder;
}
builder.Services.AddOptions<JwtSettings>()
.BindConfiguration(JwtSettings.ConfigurationSectionName)
.ValidateFluentValidation()
.ValidateOnStart();
amantinband commented
amirhessampourhossein commented
What about separating the second part and putting it in another class that implements IConfigureOptions<JwtBearerOptions>
?
amantinband commented
Yeah that's a good option as well. Feel free to create a PR for this if you'd like :)
amantinband commented
Thanks Amir! ๐ซถ