Guille
Guille

Reputation: 377

Disable a model validation on an action method in asp.net core

I want to disable a model validation on a specific Action method in a Controller. I have this scenario :

public class SomeDto
{
    public string Name { get; set; }
}

public class SomeDtoValidator : AbstractValidator<SomeDto>, ISomeDtoValidator
{
    public SomeDtoValidator ()
    {
        RuleFor(someDto=> someDto.Name).NotNull().WithMessage("Name property can't be null.");
    }
}

I have ISomeDtoValidator because I register all my validators in my own way :

public class Startup
{
    // .... constructor ....

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();
        services.AddMvc(setup => {
        //...others setups...
        }).AddFluentValidation();

        services.RegisterTypes(Configuration)
                .RegisterFluentValidation()
                .RegisterMappingsWithAutomapper()
                .RegisterMvcConfigurations();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IConfiguration configuration)
    {
        // ...
    }
}

I have this Action Method inside a Controller :

[DisableFormValueModelBinding]
public async Task<IActionResult> CreateSome(Guid someId, SomeDto someDto)
{
    //..... Manually binding someDto...

    var validator = new SomeValidator();
    validator.Validate(someDto);

    // Doing something more ........

    return Ok();
}       

I disabled the modelBinding's MVC because I want to do something before binding SomeDto and, therefore, I don't want to apply any validator on SomeDto either. So, there is any way to achieve that ?? For example, something like this :

[DisableValidator] // Or [DisableValidator(typeof(SomeDtoValidator))] whatever
[DisableFormValueModelBinding]
public async Task<IActionResult> CreateSome(Guid someId, SomeDto someDto)
{
    //..... Manually binding someDto...

    var validator = new SomeValidator();
    validator.Validate(someDto);

    // Doing something more ........

    return Ok();
}   

Upvotes: 8

Views: 8997

Answers (3)

Christopher Haws
Christopher Haws

Reputation: 1775

You can skip validation by adding the following attribute to your action methods parameter:

public ActionResult Save([CustomizeValidator(Skip = true)] Customer model) {
  // ...
}

This is described in the docs here: https://docs.fluentvalidation.net/en/latest/aspnet.html#validator-customization

Upvotes: 8

Alexey.Petriashev
Alexey.Petriashev

Reputation: 1734

You can use RuleSets.

see: https://fluentvalidation.net/start#rulesets

usage: https://fluentvalidation.net/aspnet#validator-customization

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(customer => customer.Surname).NotEmpty();
        RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
        RuleFor(customer => customer.Address).Length(20, 250);

        RuleSet("Names", () =>
        {
            RuleFor(x => x.Surname).NotNull();
            RuleFor(x => x.Forename).NotNull();
        });

        RuleSet("Empty", () =>
        {
        });
    }
}

Test code:

        Customer customer = new Customer();
        var validator = new CustomerValidator();
        var validationResult = validator.Validate(customer, ruleSet: "Names");
        // 2 errors: Surname and Forname
        validationResult = validator.Validate(customer, ruleSet: "Empty");
        // no errors

You can configure RuleSet in controller:

public ActionResult SaveNoValidate([CustomizeValidator(RuleSet="Empty")] Customer customer) {
// ...
}

public ActionResult SaveValidateNames([CustomizeValidator(RuleSet="Names")] Customer customer ) {
// ...
}

Upvotes: 3

Guille
Guille

Reputation: 377

I reached my goal with @Alexey.Petriashev's help, putting only a RuleSet in the validator. When pipeline calls the validator, it doesn't make a validation because the pipeline calls are without RuleSet. Bellow is an example of how I solved the issue:

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleSet("Manually", () =>
        {
            RuleFor(x => x.Surname).NotNull();
            RuleFor(x => x.Forename).NotNull();
        });
    }
}

public ActionResult ActionWithoutValidationExecuted(Customer customer) 
{
    //..... Manually binding customer...

    var validator = new CustomerValidator();
    var validResult = validator.Validate(customer, ruleSet: "Manually");

    // Doing something more ........

    return Ok();
}

Upvotes: 2

Related Questions