C# ASP.NET MVC:通过DataAnnotation进行自定义验证

C# ASP.NET MVC:通过DataAnnotation进行自定义验证,c#,.net,asp.net-mvc,asp.net-mvc-3,data-annotations,C#,.net,Asp.net Mvc,Asp.net Mvc 3,Data Annotations,我有一个模型,它有4个属性,类型为string。我知道可以使用StringLength注释验证单个属性的长度。但是,我想验证4个属性组合的长度 MVC使用数据注释的方式是什么 我这样问是因为我是MVC新手,希望在制定自己的解决方案之前以正确的方式进行验证。您可以编写一个自定义验证属性: public class CombinedMinLengthAttribute: ValidationAttribute { public CombinedMinLengthAttribute(int m

我有一个模型,它有4个属性,类型为string。我知道可以使用StringLength注释验证单个属性的长度。但是,我想验证4个属性组合的长度

MVC使用数据注释的方式是什么


我这样问是因为我是MVC新手,希望在制定自己的解决方案之前以正确的方式进行验证。

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

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;
    }
}
自验证模型 您的模型应该实现一个接口
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) });
    }
}
公共类MyModel:IValidatableObject
{
公共字符串标题{get;set;}
公共字符串说明{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{
if(Title==null)

返回新的ValidationResult(“*”,new[]{nameof(Title)}); if(Description==null)
返回新的ValidationResult(“*”,new[]{nameof(Description)}); } }

请注意:这是一个服务器端验证。它在客户端不起作用。只有在提交表单后才会执行验证。

背景:

需要进行模型验证,以确保我们接收到的数据有效且正确,以便我们可以对这些数据进行进一步处理。我们可以用动作方法验证模型。内置的验证属性有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;}
}
要创建自定义验证属性,必须从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;
    }
}
希望这有帮助。干杯

参考资料

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;}
}
    • 为您提供了这样一种可能性:

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

      回答有点晚了,但对于正在寻找的人来说。 通过在数据注释中使用额外的属性,可以轻松做到这一点:

      public string foo { get; set; }
      public string bar { get; set; }
      
      [MinLength(20, ErrorMessage = "too short")]
      public string foobar 
      { 
          get
          {
              return foo + bar;
          }
      }
      
      就这些,真的。如果确实希望在特定位置显示验证错误,可以在视图中添加以下内容:

      @Html.ValidationMessage("foobar", "your combined text is too short")
      
      如果您想进行本地化,在视图中执行此操作会很方便


      希望这有帮助

      为了改进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);
          }
      }
      
      型号:

      [UniqueFileName(ErrorMessage = "This file name is not unique.")]
      

      请注意,需要一条错误消息,否则错误将为空。

      您看过Fluent Validation吗?它处理复杂场景的能力比数据注释要好得多。请看一看高度推荐的解决方案。。。。谢谢你的回答。我会查一查,从没听说过。Niks,Darin基本上写下了你贴在链接上的文章的解释。所以,谢谢你。。。太棒了!谢谢你的回答,我接受了你的回答。其实觉得有点尴尬。你写出了整个解决方案!呵呵。只需更改IsValid函数即可检查最大长度。这是公认的解决此类问题的MVC解决方案吗?@Dannyvanderkran,是的,这是公认的方式。当然,这太糟糕了,我从未使用过它,而是使用FluentValidation.NET来执行验证。这里:。您可以为视图模型编写一个简单的验证器,它可能看起来像这样(一行代码):
      this.RuleFor(x=>x.Foo).Must((x,Foo)=>x.Foo.Length+x.Bar.Length+x.Baz.Length<20)。现在看一下我的答案中的代码,您需要使用数据注释编写代码,并告诉我您更喜欢哪一个。与命令式模型相比,声明式验证模型非常差。这有点晚了,但是有人知道为了允许自定义数据注释,是否必须“打开”不同的设置吗?我知道在web.config文件中为非结构化js添加一个名称空间,但是在其他任何地方?我整个上午都在寻找这个!我已经完成了,不幸的是,当调用
      IsValid
      时,
      validationContext
      为空。知道我做错了什么吗-(感谢您回答Andrei。虽然您的解决方案也可行,但我选择Darin的,因为它更易于重用。返回新的ValidationResult(“标题是强制性的。”,“标题”);将添加属性名称,在必要时可用于分组验证错误以供显示。请注意,只有在所有验证属性都通过验证后才调用此验证方法。这对我来说非常有效,因为我的验证非常具体。添加自定义属性对我来说太过分了,因为验证没有进行这就是我想要的。谢谢!这太棒了!我的祈祷得到了回应:)刚刚找到了这个答案,节省了大量的时间。ExpressiveAnnotation非常出色!