locked
How to validate for each input using fluentvalidation? RRS feed

  • Question

  • User521171331 posted

    currently I have this class which inherit from AbstractValidator (fluentvalidation) which I have added some validation rules for some properties. The thing is I could only validate everything when the user finish entering all the input. How do I start to validate upon each input instead?

    public class BankAccountValidator : AbstractValidator<BankAccount>
    {
        public BankAccountValidator()
        {
            CascadeMode = CascadeMode.StopOnFirstFailure;
    
            RuleFor(x => x.NRIC).Matches(@"^\d{6}-\d{2}-\d{4}$")
                .WithMessage("Invalid NRIC format. Example of valid NRIC format, 900210-10-8080");                  
    
            RuleFor(x => x.PinCode).Must(x => x.ToString().Length == 6)
                .WithMessage("Enter 6 digits for ATM Card Pin code.");
    
        }        
    }
     public BankAccount getBankAccountForm()
        {
            var newBankAccountForm = new BankAccount();
            var bankAccountValidator = new BankAccountValidator();
    
            newBankAccountForm.NRIC = Console.ReadLine();
            newBankAccountForm.PinCode = int.Parse(Console.ReadLine());
    
    
            ValidationResult validationResult = bankAccountValidator.Validate(newBankAccountForm);
            if (validationResult.IsValid == false)
            {
                foreach (var failure in validationResult.Errors)
                {
                    // failure.PropertyName 
                    messagePrinter.PrintMessage($"Error: {failure.ErrorMessage}", false);
                    return null;
                }
            }
    
            return newBankAccountForm;
        }

    Currently, the above code works but it will only validate after user completed entering all the input. What I wish is, if the first input fails, it will show the validation error message and let user re-enter until validation pass. Then user can enter the subsequent input.

    Wednesday, July 31, 2019 12:50 AM

All replies

  • User-474980206 posted
    You would make a rule set for each field, and call the rule set for that field.

    As this is a mvc forum, it’s not clear what you intend to do. Normally server validation is done with a form post of all fields. If validation is done on field exit, this is normally done with a client validation library.
    Wednesday, July 31, 2019 1:31 AM
  • User521171331 posted

    Oh ya, I should have mentioned that my project is console. My post related to fluentvalidation and console. The reason why I posted here because I saw someone posted on fluentvalidation here. 

    Anyway, so you mean for each property, I should create a class which inherit from AbstractValidator?

    Wednesday, July 31, 2019 1:46 AM
  • User1520731567 posted

    Hi ngaisteve1,

    What I wish is, if the first input fails, it will show the validation error message and let user re-enter until validation pass. Then user can enter the subsequent input.

    I suggest you could add the remote validator and hook into jQuery unobtrusive validation framework.

    For that we need to create a class which inherits from FluentValidationPropertyValidator and specify the correct client validation rule.

    For example:

    public class UniqueEmailPropertyValidator : FluentValidationPropertyValidator
    {
        public UniqueEmailPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
            : base(metadata, controllerContext, rule, validator)
        {
        }
    
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            if (!this.ShouldGenerateClientSideRules())
                yield break;
    
            var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyName);
            string message = formatter.BuildMessage(Validator.ErrorMessageSource.GetString());
    
            var rule = new ModelClientValidationRule
            {
                ValidationType = "remote",
                ErrorMessage = message
            };
            rule.ValidationParameters.Add("url", "/api/validation/uniqueemail");
    
            yield return rule;
        }
    
    }

    This will generate the correct data-val- attributes for the unobtrusive validation. At runtime the validation will be hooked up using the remote validation adapter.

    Next we need to hook this property validator into the FluentValidation framework. We do that in the AutofacConfig class where we configure FluentValidation. Notice the call to provider.Add(typeof(YourcustomValidate)..... This associates the client validation with our YourcustomValidate, so the correct client validation codes get rendered.

    FluentValidationModelValidatorProvider.Configure(provider =>
    {
        provider.ValidatorFactory = new AutofacValidatorFactory(container);
        provider.AddImplicitRequiredValidator = false;
    
        provider.Add(typeof(YourcustomValidate), (metadata, context, description, validator) => new UniqueEmailPropertyValidator(metadata, context, description, validator));
    });

    The last bit is to write the ASP.NET API Controller which will be called by the remote validator to validate for the existence of an email address. For use with the remote validator this API method should simply return true or false to indicate success or failure.

     More details,you could refer to:

    https://www.jerriepelser.com/blog/remote-client-side-validation-with-fluentvalidation/

    Best Regards.

    Yuki Tao

    Wednesday, July 31, 2019 5:33 AM
  • User521171331 posted

    Thanks Yuki Tao. Will try that out soon.

    Wednesday, July 31, 2019 6:16 AM
  • User-474980206 posted

    note: the above is for integrating fluent with the MVC validation library, and javascript making remote validation calls via javascript. 

    Wednesday, July 31, 2019 8:01 PM