65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC中使用DataAnnotations实现自定义验证的入门教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (18投票s)

2014 年 4 月 4 日

CPOL

4分钟阅读

viewsIcon

60432

downloadIcon

838

在本文中,我们将了解如何通过在ASP.NET MVC中使用自定义数据注释来实现自定义验证。

引言

在本文中,我们将了解如何通过在ASP.NET MVC中使用自定义数据注释来实现自定义验证,即在ASP.NET MVC中实现自定义验证属性。

背景

在我之前的一篇文章中,我曾讨论过如何在ASP.NET MVC应用程序中使用DataAnnotations来验证Model类。 ASP.NET MVC中验证模型数据和非干扰客户端验证的入门教程[^]。

在同一篇文章中,我们还看到了如何使用简单的脚本包含来获得开箱即用的非干扰客户端验证支持。

我们已经看到,使用数据注释技术,我们可以执行以下验证:

  • 必填字段:RequiredAttribute
  • 限制用户输入的长度:StringLengthAttribute
  • 基于正则表达式的输入约束:RegularExpressionAttribute

那么,如果我们有执行自定义验证的需求怎么办?使用这种DataAnnotation技术是否可以执行自定义验证?在本文中,我们将讨论如何通过使用数据注释来为Model属性执行自定义验证,即实现自定义验证属性。

注意:上述文章展示了如何执行这些验证,请参阅该文章以了解有关这些验证的更多信息。在本文中,我们将只讨论自定义验证。

使用代码

现在,为了理解使用数据注释的自定义验证,我将继续使用上一篇文章中的示例应用程序。因此,让我们快速了解一下现有应用程序中的内容。

数据库

在此应用程序中,我们有一个单表数据库。此表(称为Contacts)包含联系人的信息。

现在,在此表中,所有字段都不能为空,即用户必须填写。

  • FirstName:varchar(50)
  • LastName:varchar(50)
  • Address:varchar(100)
  • PhoneNumber:varchar(15)
  • eMail:varchar(35)
  • Age:INT

注意:本文章添加了Age字段以演示自定义验证规则。

模型、视图和控制器

为了执行数据访问,我们使用实体框架数据库优先的方法。所以我们的联系人实体看起来像

该应用程序包含用于对模型执行CRUD操作的视图。用于执行这些操作的控制器看起来像

public class ContactController : Controller
{
    private SampleDbEntities db = new SampleDbEntities();

    public ViewResult Index()
    {
        return View(db.Contacts.ToList());
    }

    public ViewResult Details(int id)
    {
        Contact contact = db.Contacts.Single(c => c.ID == id);
        return View(contact);
    }

    public ActionResult Create()
    {
        return View();
    } 

    [HttpPost]
    public ActionResult Create(Contact contact)
    {
        if (ModelState.IsValid)
        {
            db.Contacts.AddObject(contact);
            db.SaveChanges();
            return RedirectToAction("Index");  
        }

        return View(contact);
    }
         
    public ActionResult Edit(int id)
    {
        Contact contact = db.Contacts.Single(c => c.ID == id);
        return View(contact);
    }

    [HttpPost]
    public ActionResult Edit(Contact contact)
    {
        if (ModelState.IsValid)
        {
            db.Contacts.Attach(contact);
            db.ObjectStateManager.ChangeObjectState(contact, EntityState.Modified);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(contact);
    }
 
    public ActionResult Delete(int id)
    {
        Contact contact = db.Contacts.Single(c => c.ID == id);
        return View(contact);
    }

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {            
        Contact contact = db.Contacts.Single(c => c.ID == id);
        db.Contacts.DeleteObject(contact);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}

现有的验证规则

为了在我们的Model类中使用DataAnnotation属性实现验证,我们创建了一个部分类并在其上添加了数据注释。

[MetadataType(typeof(ContactMetaData))]
public partial class Contact
{
}

部分类带有MetadataType属性,该属性存在于DataAnnotations命名空间中。这表明该Model类的元数据将在ContactMetaData类中。因此,这个ContactMetaData类将是我们放置所有验证逻辑的地方。这个元数据类包含与它关联的Model类相同的公共属性。

上一篇文章中已实现了以下验证规则:

  • 所有字段都是必填的。
  • 用户输入的长度不应超过相应字段的长度。
  • PhoneNumber应仅包含数字。
  • eMail应为正确的电子邮件格式。

实现自定义验证

现在,在这篇文章中,我们将尝试在同一应用程序中实现以下自定义验证:

  • 录入任何联系人的最低年龄应为18岁。
  • 联系人的电话号码应唯一。即,用户不应为多个联系人输入相同的电话号码。

现在,让我们看看如何使用数据注释技术来实现这些自定义验证。为此,我们需要创建自定义验证属性。

要创建自定义验证属性,我们需要创建一个派生自ValidationAttribute的Attribute类。让我们尝试实现第一个自定义验证规则,即“录入任何联系人的最低年龄应为18岁”。为此,让我们创建一个名为MinimumvalueAttribute的自定义属性类。

public class MinimumvalueAttribute : ValidationAttribute
{
}

我们需要在此类中重写IsValid函数,以便执行我们的自定义验证。让我们在属性的构造函数中获取指定的最小值,然后在IsValid函数中执行实际验证。

public class MinimumvalueAttribute : ValidationAttribute
{
    private int m_minimumValue;

    public MinimumvalueAttribute(int value)
    {
        m_minimumValue = value;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null) // lets check if we have some value
        {
            if (value is int) // check if it is a valid integer
            {
                int suppliedValue = (int)value;
                if (suppliedValue < m_minimumValue)
                {
                    // let the user know about the validation error
                    return new ValidationResult("Minimum value for this field should be " + m_minimumValue);
                }
            }
        }

        return ValidationResult.Success;
    }
}

现在我们已经准备好了包含自定义验证逻辑的自定义属性。现在,让我们在模型中使用此属性,将我们的自定义验证逻辑与模型属性关联起来。

class ContactMetaData
{
    /*
    .
    . Other model properties
    .
    */

    [Required(ErrorMessage="Age is Required")]
    [Minimumvalue(18)] // Our custom attribute
    public int Age { get; set; }
}

现在,如果我运行应用程序并输入小于18的值,我将收到一个验证错误。

现在,让我们用同样的方式实现第二个自定义验证规则,即“联系人的电话号码应唯一”。为了实现这一点,我们将再次定义我们的自定义属性,并在属性的IsValid函数中检查电话号码是否已存在于数据库中。

public class UniquePhoneNumberAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string number = value as string;
        Contact contact = validationContext.ObjectInstance as Contact;

        if (number != null) 
        {
            using (SampleDbEntities db = new SampleDbEntities())
            {
                var contactFound = db.Contacts.FirstOrDefault(item => item.PhoneNumber.Trim().Equals(number.Trim(), StringComparison.OrdinalIgnoreCase));
                if (contactFound != null && contactFound.ID != contact.ID)
                {
                    return new ValidationResult("Same phone number exists in the application.");
                }
            }
        }

        return ValidationResult.Success;
    }
}

现在,让我们配置ContactMetaData类以使用此自定义属性来验证电话号码。

class ContactMetaData
{
    /*
    .
    . Other model properties
    .
    */

    [Required(ErrorMessage = "Phone Number is required")]
    [StringLength(15, ErrorMessage = "Phone Number length Should be less than 15")]
    [RegularExpression(@"^[0-9]{0,15}$", ErrorMessage = "PhoneNumber should contain only numbers")]
    [UniquePhoneNumber]  // OUR CUSTOM ATTRIBUTE
    public string PhoneNumber { get; set; }
}

在这里,我们正在检查是否同一电话号码已为其他用户存在。如果存在,我们将向用户显示验证错误消息。让我们运行应用程序并查看结果。

现在我们有了一个使用Data annotations执行自定义验证的应用程序。

关注点

在本文中,我们通过实现自定义验证属性来研究如何执行基于自定义数据注释的验证。本文是从初学者的角度撰写的。我希望它有所帮助。

历史

  • 2014年4月4日:初版
© . All rights reserved.