Best Client-Side Validation Approach for Each Custom Rule in FluentValidation

I use FluentValidation in my ASP.NET MVC 4 application. I already knew that some rules automatically generate attributes for the jQuery validation library. And this script library already knew that it should check, for example, in the case data-rule-required, data-rule-rangeetc.

I know that there are some features in FluentValidation, but they are not client-side. For example: .Equal(true). I checked @DarinDimitrov's answer here and implemented it without any problems.

But I do not want to always create a new class that is inherited from FluentValidationPropertyValidator. And we have to add this to a provider like this in global.asax:

provider.Add(typeof(EqualValidator), (metadata, context, description, validator) => new EqualToValueClientRule(metadata, context, description, validator));

In this case, it is EqualValidatoralready implemented in FluentValidation. But what if we created a validator with a keyword When. For example, I have:

this.RuleFor(phone => phone.Digits)
    .Length(7)
        .When(phone => phone.PrefixId == 2)
        .WithMessage("Numbers in 2nd city must contain 7 characters");

this.RuleFor(phone => phone.Digits)
    .Length(7)
        .When(phone => phone.PrefixId > 64)
        .WithMessage("Mobile number must contain 7 characters");

this.RuleFor(phone => phone.Digits)
    .Length(5)
        .When(phone => phone.PrefixId != 2)
        .WithMessage("Numbers in other cities must contain 5 characters")

Of course, I can check this with jQuery / JavaScript without any problems. But this approach is not very good. And in other cases, you need to write so much code to create custom attributes on the client side and add a new function to the adapter. Or just use jQuery / JavaScript? Or something else? Maybe we can add the name of the JavaScript function in FluentValidationPropertyValidator?

What will you advice me?

+4
source share
1 answer

, - , PropertyValidator IClientValidatable. . .

, :

public class MustFitToPhonePrefix<TModel, TProperty> : PropertyValidator, IClientValidatable
    {
        private string dependencyElement;

        public MustFitToPhonePrefix(Expression<Func<TModel, TProperty>> expression)
            : base("Format is wrong")
        {
            dependencyElement = (expression.Body as MemberExpression).Member.Name;
        }

        // Server side validation
        protected override bool IsValid(PropertyValidatorContext context)
        {
            // Instance of the class which contains property which must be validated 
            var phone = context.ParentContext.InstanceToValidate as PhoneDetail;

            ...
            // Custom logic
            ...

            // Everything is valid
            return true;
        }

        // Generate jquery unobtrusive attributes
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = this.ErrorMessageSource.GetString(), // default error message
                ValidationType = "fittoprefix" // name of the validatoin which will be used inside unobtrusive library
            };

            rule.ValidationParameters["prefixelement"] = dependencyElement; // html element which includes prefix information
            yield return rule;
        }

:

// Will check if the phone number fits to phone prefix
$.validator.addMethod('fittoprefix', function (value, element, params) {
    var parent = getParentPropertyName(element);
    var prefixId = $("#{0}_{1}".format(parent, params.prefixelement)).val();
    var digitsLength = $(element).val().Length;

    ...
    // Custom logic
    ...

    return true;
});

// Registration - Will check if the phone number fits to phone prefix
$.validator.unobtrusive.adapters.add('fittoprefix', ['prefixelement'], function (options) {
    options.rules['fittoprefix'] = options.params;
    if (options.message != null) {
        options.messages['fittoprefix'] = options.message;
    }
});

, :

   this.RuleFor(m => m.Digits)
       .SetValidator(new MustFitToPhonePrefix<PhoneDetail, int>(m => m.PrefixId));
+2

Source: https://habr.com/ru/post/1585048/


All Articles