For my .Net 5 workerservice app I want to validate options by implementing the IValidateOptions interface but don't want to write my own error messages. That's why I want to make use of the package FluentValidation.AspNetCore.
Given the model
namespace App.Models
{
public class MyOptions
{
public string Text { get; set; }
}
}
I added validation rules
namespace App.ModelValidators
{
public class MyOptionsValidator : AbstractValidator<MyOptions>
{
public MyOptionsValidator()
{
RuleFor(model => model.Text).NotEmpty();
}
}
}
Next I'm using this validator inside the validation
namespace App.OptionsValidators
{
public class MyOptionsValidator : IValidateOptions<MyOptions>
{
private readonly IValidator<MyOptions> _validator;
public MyOptionsValidator(IValidator<MyOptions> validator)
{
_validator = validator;
}
public ValidateOptionsResult Validate(string name, MyOptions options)
{
var validationResult = _validator.Validate(options);
if (validationResult.IsValid)
{
return ValidateOptionsResult.Success;
}
return ValidateOptionsResult.Fail(validationResult.Errors.Select(validationFailure => validationFailure.ErrorMessage));
}
}
}
Lastly I setup the DI container
services.AddTransient<IValidator<MyOptions>, ModelValidators.MyOptionsValidator>();
services.AddSingleton<IValidateOptions<MyOptions>, OptionsValidators.MyOptionsValidator>();
services.Configure<MyOptions>(configuration.GetSection("My"));
I would like to know if this can be simplified?
Maybe I can just implement the IValidateOptions interface, avoid the AbstractValidator and write fluent rules inside the .Validate() method?
Sample code what I want to achieve
namespace App.OptionsValidators
{
public class MyOptionsValidator : IValidateOptions<MyOptions>
{
public ValidateOptionsResult Validate(string name, MyOptions options)
{
var validationResult = options.Text.Should.Not.Be.Empty();
if (validationResult.IsValid)
{
return ValidateOptionsResult.Success;
}
return ValidateOptionsResult.Fail(validationResult.ErrorMessage);
}
}
}
so I don't need the AbstractValidator<MyOptions> anymore.
My first approach I'm not sure about
Instead of using FluentValidation I'm using DataAnnotations.
- I added the
[Required]attribute to theTextproperty - I completely removed the class
MyOptionsValidator : AbstractValidator<MyOptions> - I only register this in the DI setup
.
services.AddSingleton<IValidateOptions<MyOptions>, OptionsValidators.MyOptionsValidator>();
services.Configure<MyOptions>(configuration.GetSection("My"));
Inside MyOptionsValidator I validate the options like so
public ValidateOptionsResult Validate(string name, MyOptions options)
{
var validationResults = new List<ValidationResult>();
if (!Validator.TryValidateObject(options, new ValidationContext(options), validationResults, true))
{
return ValidateOptionsResult.Fail(validationResults.Select(validationResult => validationResult.ErrorMessage));
}
return ValidateOptionsResult.Success;
}
but maybe there are still better ways :)

