Rasik
Rasik

Reputation: 2420

Stop all further validation if multiple validation for first field fails

I am trying to write the rules for validating field for the validation.

At first i want to check if Location Id is empty, null or if that exist in the database, and then only processed further for other validation.

But, with the code i used, only check if empty, it does not stop if Location Id does not exist in the database.

Register Model

public class RegisterModel
{
    public long LocationId {get;set;}
    public long FirstName {get;set;}
    public long LastName {get;set;}

    //...other property to be added
}

JSON i am passing to API:

{
    "FirstName": "John",
    "LocationId": "1234534",
}

The location id does not exist in the database: But i am getting the response as:

{
    "Errors": [
        {
            "FieldName": "LastName",
            "Message": "'Last Name' must not be empty."
        },
        {
            "FieldName": "LocationId",
            "Message": "Invalid request."
        }
    ]
}

Validation rule i am using:

public class RegisterModelValidator : AbstractValidator<RegisterModel>
{
    private readonly DbContext _context;

    public RegisterModelValidator(DbContext context)
    {
        this._context = context;
        this.CascadeMode = CascadeMode.StopOnFirstFailure;
        RuleFor(req => req.LocationId)
          .NotEmpty().WithMessage("param1 is missing.")
          .Must(IsValidRequest).WithMessage("Invalid request.");

        When(x => x.LocationId != null, () => {

            RuleFor(x => x.FirstName).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEmpty();
            RuleFor(x => x.LastName).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEmpty();

        });

    }

    private bool IsValidRequest(string req)
    {
        var locationId = long.TryParse(req, out long result) ? result : 0;
        return _context.Locations.Any(x => x.LocationExtId == locationId);
    }

    private bool BeAValidDate(string value)
    {
        DateTime date;
        return DateTime.TryParse(value, out date);
    }
}

In my condition what i want is if the location id is missing or does not exist in the database, the validation should stop immediately, it should not check for the other field.

Upvotes: 0

Views: 360

Answers (1)

HariHaran
HariHaran

Reputation: 4179

If you look at the docs here, its mentioned as

Setting the cascade mode only applies to validators within the same RuleFor chain. Changing the cascade mode does not affect separate calls to RuleFor. If you want prevent one rule from running if a different rule fails, you should instead use Dependent Rules (below)

So can you try it like this using Dependent Rules

RuleFor(x => x.FirstName).NotNull().NotEmpty()
          .DependentRules(d => d.RuleFor(req => req.LocationId)
          .NotEmpty().WithMessage("param1 is missing.")
          .Must(IsValidRequest).WithMessage("Invalid request."));

But i see if we use it like this, i think it should be repeated for multiple properties.

or a better option for you is using PreValidate since

At first i want to check if Location Id is empty, null or if that exist in the database

Prevalidate a property

Upvotes: 1

Related Questions