question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Could AddFluentValidationAutoValidation() take a filter parameter so we can opt in/out of automatic validtion?

See original GitHub issue

Is 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:closed
  • Created 6 months ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
JeremySkinnercommented, Mar 29, 2023

Published FluentValidation.AspNetCore 11.3.0 with this change. Thanks for contributing!

1reaction
JeremySkinnercommented, Mar 24, 2023

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 in FluentValidationModelValidator( https://github.com/FluentValidation/FluentValidation.AspNetCore/blob/main/src/FluentValidation.AspNetCore/FluentValidationModelValidatorProvider.cs#L142)

Read more comments on GitHub >

github_iconTop Results From Across the Web

The future of our ASP.NET Integration package · Issue ...
Could AddFluentValidationAutoValidation() take a filter parameter so we can opt in/out of automatic validtion? #2091.
Read more >
ASP.NET Core Web API - FluentValidationMvcExtensions. ...
In ASP.NET Core-6 Web API, I am using FluentValidation.AspNetCore(11.2.1). I have this code in the Program.cs: builder.Services.AddMvc().
Read more >
ASP.NET Core — FluentValidation documentation
With automatic validation, FluentValidation plugs into the validation pipeline that's part of ASP.NET Core MVC and allows models to be validated before a ......
Read more >
Minimal API validation with ASP.NET 7.0 Endpoint Filters
NET 7.0 included support for Minimal API endpoint filters. This post looks at how you can use this feature to validate requests using...
Read more >
FluentValidation in ASP.NET WebAPI | by Adam Connelly
If the parameter isn't null, and we want to validate it, we try to find a validator that can validate it, and if...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found