ASP.NET MVC:DataAnnotation的自定义验证

Dan*_*aan 107 .net c# asp.net-mvc data-annotations asp.net-mvc-3

我有一个具有4个属性的模型,其类型为字符串.我知道您可以使用StringLength注释验证单个属性的长度.但是,我想验证4个属性组合的长度.

使用数据注释执行此操作的MVC方式是什么?

我问这个是因为我是MVC的新手,并希望在制作我自己的解决方案之前以正确的方式做到这一点.

Dar*_*rov 170

您可以编写自定义验证属性:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可能有一个视图模型并用它装饰它的一个属性:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 这里:http://fluentvalidation.codeplex.com/.您可能刚刚为视图模型编写了一个简单的验证器,它可能看起来像这样(单行代码):`this.RuleFor(x => x.Foo).Must((x,foo)=> x. Foo.Length + x.Bar.Length + x.Baz.Length <20).WithMessage("Foo,Bar和Baz属性的组合最小长度应该大于20");`.现在看一下我的答案中的代码,你需要用数据注释来写,并告诉我你喜欢哪一个.与命令式模型相比,声明性验证模型非常差. (11认同)
  • @DannyvanderKraan,是的,这是公认的方式.当然,这非常糟糕,我从不使用它,而是使用FluentValidation.NET来执行验证. (7认同)
  • 谢谢你的回答,我接受了你的回答.实际上感觉有点尴尬.你写出了整个解决方案!呵呵.只需更改IsValid函数即可检查最大长度.对于这些类型的问题,这是可接受的MVC解决方案吗? (4认同)

And*_*rei 90

自我验证的模型

您的模型应该实现一个接口IValidatableObject.将验证代码放在Validate方法中:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意:这是服务器端验证.它不适用于客户端.您只有在提交表单后才会进行验证.

  • yield return new ValidationResult("标题是强制性的.","标题"); 将添加属性名称,如果需要,可用于分组验证错误以供显示. (6认同)
  • 请注意,只有在所有验证属性都通过验证后才会调用此验证方法. (5认同)
  • 这对我很有用,因为我的验证非常具体.添加自定义属性对我来说太过分了,因为验证不会被重复使用. (3认同)

jwa*_*zko 23

ExpressiveAnnotations为您提供了这样的可能性:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }
Run Code Online (Sandbox Code Playgroud)


Jam*_*mie 10

为了改善Darin的答案,它可以缩短一点:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}
Run Code Online (Sandbox Code Playgroud)

模型:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]
Run Code Online (Sandbox Code Playgroud)

请注意,需要输出错误消息,否则错误将为空.


Yas*_*ser 9

背景:

需要进行模型验证,以确保我们收到的数据有效且正确,以便我们可以使用此数据进行进一步处理.我们可以在动作方法中验证模型.内置的验证属性是Compare,Range,RegularExpression,Required,StringLength.但是,我们可能有一些场景,其中我们需要除内置验证属性之外的验证属性.

自定义验证属性

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

要创建自定义验证属性,您必须从ValidationAttribute派生此类.

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.干杯!

参考