c# - ASP.NET MVC 自定义多字段验证

标签 c# asp.net asp.net-mvc validation data-annotations

我正在开发一个 ASP.NET MVC 5.2.3 自定义数据注释,用于在 Visual Studio 2015 中进行验证。它需要采用任意数量的字段,并确保如果一个字段有值,则它们都必须有值;如果它们都是空的/空白的,那应该没问题。

一些例子有帮助:

但是,我不确定如何在要验证的字段数量未知的情况下进行客户端验证。

如何使用 IClientValidatable 接口(interface)的 GetClientValidationRules() 方法的实现将其传递给客户端?

此外,如何将这个新的数据注释应用于我的 View 模型的属性?会是这个样子吗?

[MultipleRequired("AppNumber", "UserId", /* more fields */), ErrorMessage = "Something..."]
[DisplayName("App #")]
public int AppNumber { get; set; }

[DisplayName("User ID")]
public int UserId { get; set; }

这是我使用 MultipleRequiredAttribute 自定义数据注释类所能得到的:

public class MultipleRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _fields;
    public MultipleRequiredAttribute(params string[] fields)
    {
        _fields = fields;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // If any field has value, then all must have value
        var anyHasValue = _fields.Any(f => !string.IsNullOrEmpty(f));

        if (!anyHasValue) return null;

        foreach (var field in _fields)
        {
            var property = validationContext.ObjectType.GetProperty(field);
            if (property == null)
                return new ValidationResult($"Property '{field}' is undefined.");

            var fieldValue = property.GetValue(validationContext.ObjectInstance, null);

            if (string.IsNullOrEmpty(fieldValue?.ToString()))
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "multiplerequired"
        };
    }
}

谢谢。

最佳答案

为了获得客户端验证,您需要使用 .Add() 方法在 ModelClientValidationRule 中传递“其他属性”的值规则 ValidationParameters 属性,然后编写客户端脚本将规则添加到 $.validator

但首先,您的属性还有一些其他问题需要解决。首先,只有当您应用属性的属性值为 null 时,您才应该执行您的 foreach 循环。其次,如果其中一个“其他属性”不存在,则返回 ValidationResult 会令用户感到困惑和无意义,您应该忽略它。

属性代码应该是(注意我改了属性的名字)

public class RequiredIfAnyAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _otherProperties;
    private const string _DefaultErrorMessage = "The {0} field is required";

    public RequiredIfAnyAttribute(params string[] otherProperties)
    {
        if (otherProperties.Length == 0) // would not make sense
        {
            throw new ArgumentException("At least one other property name must be provided");
        }
        _otherProperties = otherProperties;
        ErrorMessage = _DefaultErrorMessage;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null) // no point checking if it has a value
        {
            foreach (string property in _otherProperties)
            {
                var propertyName = validationContext.ObjectType.GetProperty(property);
                if (propertyName == null)
                {
                    continue;
                }
                var propertyValue = propertyName.GetValue(validationContext.ObjectInstance, null);
                if (propertyValue != null)
                {
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
                }
            }
        }
        return ValidationResult.Success;
    }
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ValidationType = "requiredifany",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
        };
        / pass a comma separated list of the other propeties
        rule.ValidationParameters.Add("otherproperties", string.Join(",", _otherProperties));
        yield return rule;
    }
}

然后脚本将是

sandtrapValidation = {
    getDependentElement: function (validationElement, dependentProperty) {
        var dependentElement = $('#' + dependentProperty);
        if (dependentElement.length === 1) {
            return dependentElement;
        }
        var name = validationElement.name;
        var index = name.lastIndexOf(".") + 1;
        var id = (name.substr(0, index) + dependentProperty).replace(/[\.\[\]]/g, "_");
        dependentElement = $('#' + id);
        if (dependentElement.length === 1) {
            return dependentElement;
        }
        // Try using the name attribute
        name = (name.substr(0, index) + dependentProperty);
        dependentElement = $('[name="' + name + '"]');
        if (dependentElement.length > 0) {
            return dependentElement.first();
        }
        return null;
    }
}

$.validator.unobtrusive.adapters.add("requiredifany", ["otherproperties"], function (options) {
    var element = options.element;
    var otherNames = options.params.otherproperties.split(',');
    var otherProperties = [];
    $.each(otherNames, function (index, item) {
        otherProperties.push(sandtrapValidation.getDependentElement(element, item))
    });
    options.rules['requiredifany'] = {
        otherproperties: otherProperties
    };
    options.messages['requiredifany'] = options.message;
});

$.validator.addMethod("requiredifany", function (value, element, params) {
    if ($(element).val() != '') {
        // The element has a value so its OK
        return true;
    }
    var isValid = true;
    $.each(params.otherproperties, function (index, item) {
        if ($(this).val() != '') {
            isValid = false;
        }
    });
    return isValid;
});

关于c# - ASP.NET MVC 自定义多字段验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42032739/

相关文章:

asp.net - 在设计器 View 中打开项目时 Visual Studio 崩溃

c# - 如何使用数据注释验证 IEnumerable<HttpPostedFiles>

asp.net-mvc - Aurelia 服务器端 View (ASP.NET MVC)

css - WebGrid header 不会使用 CSS 更改背景颜色 - ASP.NET MVC 3

c# - 如何将字符串中间的字母大写?

c# - 动态不包含项目引用中属性的定义

c# - 使用字符串引用 DLL 类

javascript - 如何在 preventDefault() 之后启用默认链接按钮

javascript - 检测用户是否在新选项卡中打开链接并重定向到新网址

c# - 将 List<int> 添加到 mysql 参数