【问题标题】:Best approach for Client-side validation for each custom rule in FluentValidationFluentValidation 中每个自定义规则的客户端验证的最佳方法
【发布时间】:2015-04-28 07:24:06
【问题描述】:

我在我的 Asp.Net MVC 4 应用程序中使用 FluentValidation。我已经知道有些规则会自动为 jQuery 验证库生成属性。而且这个脚本库已经知道它必须检查什么,例如data-rule-requireddata-rule-range等等。

我知道 FluentValidation 中有一些功能,但这些功能不包括在客户端。例如:.Equal(true)。 我已经检查了@DarinDimitrov 答案here 并没有任何问题地实现了这个。

但是,我不想总是创建从FluentValidationPropertyValidator 继承的新类。我们必须像在 global.asax 中那样将它添加到提供者:

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

在这种情况下,EqualValidator 已经在 FluentValidation 中实现。但是,如果我们创建了一个带有 When 关键字的验证器呢?例如,我有:

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")

当然,我可以使用 jQuery/JavaScript 毫无问题地进行检查。但是,这种方法并不好。在其他情况下,您必须编写大量代码以在客户端生成自定义属性并向适配器添加新功能。或者,只使用 jQuery/JavaScript?还是别的什么?也许我们可以将 JavaScript 函数名称添加到 FluentValidationPropertyValidator

你有什么推荐给我的?

【问题讨论】:

  • 我想最好的方法是创建 PropertyValidator 类,它在服务器端始终有效,注册 javascript 函数名称,将在客户端执行。
  • @EvgenyLevin 我已经做到了。另外,我的验证器也实现了IClientValidatable。它将在客户端创建验证属性。因此,我可以在任何其他项目中轻松使用此验证器。
  • 是的,您的验证器可以作为电话验证器重复使用,但我的想法是创建“假”验证器,它只在特殊属性和适配器中注册客户端函数,调用该 js 函数,以及与规则构建器链一起使用的扩展。然后调用将如下所示:RuleFor(phone => phone.Digits).Length(7).When(...).WithMessage("...").Length(5).When(...).WithMessage("...").ClientSideRule("allPhoneValidationLogicWithWhenConditionsFunction");
  • @EvgenyLevin 我明白了。但是,我将在哪里创建客户端属性?

标签: c# asp.net-mvc asp.net-mvc-4 unobtrusive-validation fluentvalidation


【解决方案1】:

我想了很多,发现最好的方法是创建新的验证器,它继承自 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));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-14
    • 2011-03-08
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 2015-12-04
    • 1970-01-01
    • 2016-01-27
    相关资源
    最近更新 更多