如何创建自定义数据注释验证器?

64

想要创建自定义数据注释验证。有没有关于如何创建它们的有用指南/示例?

首先:
使用最小和最大长度的StringLength。我知道.NET 4可以做到这一点,但是想在.NET 3.5中完成相同的任务,如果可能的话,能够仅定义最小长度(至少x个字符)、最大长度(最多x个字符)或两者兼备(x和y之间的字符)。

其次:
使用模算术进行验证 - 如果数字是有效长度,则希望使用模11算法进行验证(我已经在JavaScript中实现了它,所以我想这只是一个简单的移植?)

更新:
第二个问题解决了,只需复制JavaScript实现并进行一些调整即可,因此不需要解决方案。

3个回答

119

要创建一个自定义的数据注释验证器,请遵循以下准则:

  1. 您的类必须继承自 System.ComponentModel.DataAnnotations.ValidationAttribute 类。
  2. 重写 bool IsValid(object value) 方法并在其中实现验证逻辑。

就这样。

重要注意事项

有时候开发人员会检查值是否为null/空并返回false。这通常是不正确的行为,因为这是由Required验证器来检查的,这意味着您的自定义验证器应该仅验证非null数据但在其他情况下返回true(请参见示例)。这将使它们可用于必填和非必填字段。

示例

public class StringLengthRangeAttribute : ValidationAttribute
{
    public int Minimum { get; set; }
    public int Maximum { get; set; }

    public StringLengthRangeAttribute()
    {
        this.Minimum = 0;
        this.Maximum = int.MaxValue;
    }

    public override bool IsValid(object value)
    {
        string strValue = value as string;
        if (!string.IsNullOrEmpty(strValue))
        {
            int len = strValue.Length;
            return len >= this.Minimum && len <= this.Maximum;
        }
        return true;
    }
}

所有属性都可以根据您的需要在属性中设置。
以下是一些示例:

[Required]
[StringLengthRange(Minimum = 10, ErrorMessage = "Must be >10 characters.")]

[StringLengthRange(Maximum = 20)]

[Required]
[StringLengthRange(Minimum = 10, Maximum = 20)]

当某个属性未设置时,其值将在构造函数中设置,因此它始终具有一个值。在上面的使用示例中,我故意添加了 Required 验证器,以便与我写的上述警告保持同步。

重要提示

因此,此验证器仍将对您的模型值(不是必需的)起作用,但当它存在时进行验证(想象一下 Web 表单中的文本字段,它不是必需的,但如果用户输入值,则必须有效)。


1
那么,如果是空值,isValid应该返回true吗? - onof
3
@onof:是的,这种情况下它应该返回 true - Robert Koritnik
@Rap 在MVC 5中对我有效。http://msdn.microsoft.com/en-us/library/cc679289(v=vs.110).aspx - demoncodemonkey
ModelState始终有效。[必填] [字符串长度范围(Minimum = 3, ErrorMessage = "必须大于3个字符。")] public string BookName { get; set; } - sm.abdullah
我该如何在global.aspx中注册这个ValidationAttribute? 我正在尝试使用以下代码:DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(NumericAttribute), typeof(???)); - mahboub_mo
显示剩余2条评论

14

使用 CustomValidationAttribute,结合一个带有以下签名的验证函数:

public static ValidationResult Validate(MyType x, ValidationContext context)

示例(字符串属性)

using System.ComponentModel.DataAnnotations;

public class MyClass
{
    [CustomValidation(typeof(MyClass), "Validate")]
    public string MyProperty { get; set; }

    public static ValidationResult Validate(string x, ValidationContext context)
    {
        return (x == "valid")
            ? new ValidationResult(null)
            : ValidationResult.Success;
    }
}

ValidationContext 上下文参数的作用是什么? - slasky
@petryuno1 如果您需要查看验证中的其他属性,可以使用它来获取模型。例如,var model = (MyClass)context.ObjectInstance; - Jason Butera

2

我知道这是一个非常老的话题,但我在找到这个答案之前一直找不到我想要的答案。

总结一下,您需要在启动时配置服务,创建适当的对象来处理您想要返回的错误:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApiBehaviorOptions(options =>
        {
            options.InvalidModelStateResponseFactory = (context) =>
            {
                var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => new ErrorModel()
               {
                   ErrorCode = ((int)HttpStatusCode.BadRequest).ToString(CultureInfo.CurrentCulture),
                    ErrorMessage = p.ErrorMessage,
                    ServerErrorMessage = string.Empty
                })).ToList();
                var result = new BaseResponse
                {
                    Error = errors,
                    ResponseCode = (int)HttpStatusCode.BadRequest,
                    ResponseMessage = ResponseMessageConstants.VALIDATIONFAIL,

                };
                return new BadRequestObjectResult(result);
            };
       });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接