Could AddFluentValidationAutoValidation() take a filter parameter so we can opt in/out of automatic validtion?
See original GitHub issueIs your feature request related to a problem? Please describe.
We are aware that “automatic validation” is no longer recommended.
We want to get ahead of the problem and move away from automatic validation. However, we don’t want to convert all validators at once, as we have 60+ legacy validators that are making use of automatic validation. Due to the size of our app, changing over all of the validators at once is risky. We would like to continue using automatic validation for the existing (legacy) validators, but enforce the use of manual validators for any new validators that get written. Over time, we would convert the legacy validators and remove automatic validation altogether.
Describe the solution you’d like
Adding a configuration filter to the AddFluentValidationAutoValidation() method would be ideal (similar to the filter option in AddValidatorsFromAssemblyContaining()
Something like this would allow us to opt-in with a list of legacy types:
var automaticValidators = new List<Type>
{
typeof(WeatherForecastCreateModelValidator),
typeof(WeatherForecastUpdateModelValidator)
};
services.AddFluentValidationAutoValidation(config =>
{
config.Filter = filter => automaticValidators.Contains(filter.ValidatorType)
});
Describe alternatives you’ve considered
I have been able to achieve opt-in functionality with a custom attribute, IValidatorInterceptor and IValidatorSelector. Automatic Validation will only run if the EnableFluentAutoValidationAttribute is present on the Validator. If not present, the interceptor will skip validation.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class EnableFluentAutoValidationAttribute : Attribute
{
}
public class CustomValidatorInterceptor : IValidatorInterceptor
{
private readonly IServiceProvider _serviceProvider;
public CustomValidatorInterceptor(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ValidationResult AfterAspNetValidation(ActionContext actionContext, IValidationContext validationContext, ValidationResult result)
{
return result;
}
public IValidationContext BeforeAspNetValidation(ActionContext actionContext, IValidationContext commonContext)
{
var IValidatorType = typeof(IValidator<>).MakeGenericType(commonContext.InstanceToValidate.GetType());
var validatorType = _serviceProvider.GetService(IValidatorType).GetType();
var enableFluentAutoValidation = Attribute.GetCustomAttribute(validatorType, typeof(EnableFluentAutoValidationAttribute)) != null;
if(enableFluentAutoValidation)
{
//if validator has EnableFluentAutoValidationAttribute, run the validation as normal by returning commentContext
return commonContext;
}
else
{
//if validator does not have this attribute, don't validate the rule
return new ValidationContext<object>(commonContext.InstanceToValidate, commonContext.PropertyChain, new NoOpValidatorSelector());
}
}
}
public class NoOpValidatorSelector : IValidatorSelector
{
public bool CanExecute(IValidationRule rule, string propertyPath, IValidationContext context)
{
return false;
}
}
In Program.cs (or Startup.cs):
services.AddFluentValidationAutoValidation();
services.AddValidatorsFromAssemblyContaining<WeatherForecastCreateModel>();
services.AddTransient<IValidatorInterceptor, CustomValidatorInterceptor>();
Attribute usage:
[EnableFluentAutoValidation]
public class WeatherForecastUpdateModelValidator : AbstractValidator<WeatherForecastUpdateModel>
{
public WeatherForecastUpdateModelValidator()
{
RuleFor(x => x.Temperature).NotEmpty();
RuleFor(x => x.Details).NotEmpty();
}
}
Additional Context
I realize it’s possible to “opt-out” of automatic validation on individual validators through CustomizeValidator(Skip=true):
public ActionResult Save([CustomizeValidator(Skip=true)] Person person)
{
// ...
}
However, I’m not aware of a way to make automatic validation happen only on an “opt-in” basis. The “opt-in” approach would be preferable for us because we have a large team and I want to make it obvious that automatic validation should not be used going forward. If we keep automatic validation enabled globally, we have to rely on individual contributors knowing that they should avoid using automatic validation.
I love your library by the way (been using it for 8+ years). Thanks!
Issue Analytics
- State:
- Created 6 months ago
- Comments:7 (4 by maintainers)
Top GitHub Comments
Published FluentValidation.AspNetCore 11.3.0 with this change. Thanks for contributing!
Thanks for the suggestion - I’m not really keen on adding new features to auto-validation as it’s essentially in an unmaintained state now, but I can see that this would be valuable for migrating away from auto validation. I’m not personally interested on working on anything related to auto validation anymore for the reasons outlined here, but if you’ve got the time to work on this and are able to put together a PR which adds the feature and also adds appropriate integration tests then I’d be happy to review it and merge it in.
Examples of how the integration tests work can be found in the FluentValidation.Tests.AspNetCore project (eg in MvcIntegrationTests although i’d probably create a separate test file for this). The logic for handling the filtering itself can be done as part of
ShouldSkip
inFluentValidationModelValidator
( https://github.com/FluentValidation/FluentValidation.AspNetCore/blob/main/src/FluentValidation.AspNetCore/FluentValidationModelValidatorProvider.cs#L142)