【ASP.NET MVC 学习笔记】- 17 Model验证

本文参考:http://www.cnblogs.com/willick/p/3434483.html

1、Model验证用于在实际项目中对用户提交的表单的信息进行验证,MVC对其提供了很好的支持。

2、ModelState 是 Controller 抽象类的一个属性,它是 MVC 处理完验证时要使用的一核心对象,提供了对验证结果的存、取和判断。所以验证用户提交的数据,最直接的方法是在Action方法中使用 ModelState 对Model对象的属性值自行判断合法性。示例:

[HttpPost] 
public ViewResult MakeBooking(Appointment appt) 
{ 
    if (string.IsNullOrEmpty(appt.ClientName)) 
    { 
        ModelState.AddModelError("ClientName", "Please enter your name"); //ModelState.AddModelError用于添加错误信息
    } 
    if (ModelState.IsValidField("Date") && DateTime.Now > appt.Date) //ModelState.IsValidField 方法用于检查用户提交的值是否能够被Model Binder成功赋值给指定的属性
    { 
        ModelState.AddModelError("Date", "Please enter a date in the future"); 
    } 
    if (!appt.TermsAccepted) 
    { 
        ModelState.AddModelError("TermsAccepted", "You must accept the terms"); 
    } 
    if (ModelState.IsValid) 
    { 
        return View("Completed", appt); 
    } else 
    { 
        return View(); 
    } 
}

3、验证消息的显示,可以简单的分为两种,一种是Model级的,另一种是属性级的。Model级示例:

@using (Html.BeginForm()) { 
    @Html.ValidationSummary()
    <p>Your name: @Html.EditorFor(m => m.ClientName)</p> 
    ...
}
//Html.ValidationSummary()还有三些重载方法:Html.ValidationSummary(bool)  、 Html.ValidationSummary(string)  和 Html.ValidationSummary(bool, string) 。
//第一个是当参数为true时,只显示Model级的验证消息(如果 ModelState.AddModelError 方法的第一个参数没有指定属性名称,则为Model级的);第二个是为所有的验证消息显示一个标题;第三个是前两个的结合。

    属性级示例:

@using (Html.BeginForm()) 
{
    @Html.ValidationSummary(true)
    <p>@Html.ValidationMessageFor(m => m.ClientName)</p>
    <p>Your name: @Html.EditorFor(m => m.ClientName)</p>
    <p>@Html.ValidationMessageFor(m => m.Date)</p>
    <p>Appointment Date: @Html.EditorFor(m => m.Date)</p>
    <p>@Html.ValidationMessageFor(m => m.TermsAccepted)</p>
    <p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms & conditions</p>
    <input type="submit" value="Make Booking" />
}

4、处理在Action方法中进行验证,默认的ModelBinder在对值进行绑定时也有验证处理。示例:

[HttpPost]
public ViewResult MakeBooking(Appointment appt) 
{
    if (ModelState.IsValid) 
    {
        return View("Completed", appt);
    } else 
    {
        return View();
    } 
}

5、对于MVC模式来说,如果把验证的规则放在自定义的 Model Binder 类中似乎并不合适。更多的时候我们会选择使用元数据的方式把验证的规则放在Model类中。示例:

public class Appointment 
{ 
    [Required] 
    public string ClientName { get; set; } 

    [DataType(DataType.Date)] 
    [Required(ErrorMessage="Please enter a date")]
  public DateTime Date { get; set; } 

    [Range(typeof(bool), "true", "true", ErrorMessage = "You must accept the terms")]
  public bool TermsAccepted { get; set; } 
}

   MVC内置的验证特性如下图:

  

6、我们也可以通过继承ValidationAttribute类自定义验证特性。示例:

public class MustBeTrueAttribute : ValidationAttribute
{ 
    public override bool IsValid(object value) 
    { 
        return value is bool && (bool)value; 
    } 
}

7、我们也可以继承内置的特性自定义验证特性。示例

public class FutureDateAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
        return base.IsValid(value) && ((DateTime)value) > DateTime.Now; 
    } 
}

8、Model级别的自定义验证。示例:

//Joe这个人星期一这天不能预约
public class NoJoeOnMondaysAttribute : ValidationAttribute 
{ 
    public NoJoeOnMondaysAttribute() 
    { 
        ErrorMessage = "Joe cannot book appointments on Mondays"; 
    } 

    public override bool IsValid(object value) 
    { 
        Appointment app = value as Appointment; 
        if (app == null || string.IsNullOrEmpty(app.ClientName) || app.Date == null) 
{
return true; }
else
     {
return !(app.ClientName == "Joe" && app.Date.DayOfWeek == DayOfWeek.Monday); } } }
[NoJoeOnMondays] 
public class Appointment 
{ 
    ...
}

9、Model 的自验证,即在 Model 类内部编写验证逻辑方法,通过实现 IValidatableObject 接口来告诉 MVC 该某个 Model 是否为自验证的 Model。示例:

public class Appointment : IValidatableObject 
{
public string ClientName { get; set; } [DataType(DataType.Date)] public DateTime Date { get; set; } public bool TermsAccepted { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{ List
<ValidationResult> errors = new List<ValidationResult>(); if (string.IsNullOrEmpty(ClientName)) { errors.Add(new ValidationResult("Please enter your name")); } if (DateTime.Now > Date) { errors.Add(new ValidationResult("Please enter a date in the future")); } if (errors.Count == 0 && ClientName == "Joe" && Date.DayOfWeek == DayOfWeek.Monday) { errors.Add(new ValidationResult("Joe cannot book appointments on Mondays")); } if (!TermsAccepted) { errors.Add(new ValidationResult("You must accept the terms")); } return errors; } }

    如果一个 Model 实现了 IValidatableObject 接口,MVC 会在 Model Binder 为 Model 的每个属性赋值后调用Validate方法。相对于在 Action 方法中的验证,这种 Model 自验证更为灵活,而且把验证逻辑放在对应的Model中,保证了代码的一致性,方便维护。

10、客户端验证在Web.config中有两个开关,默认都是启用的,如下:

<appSettings> 
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/> 
</appSettings> 

    要启用客户端验证,这两个值都需要设为true。你也可以在单个的View中通过设置HtmlHelper.ClientValidationEnabled 和 HtmlHelper.UnobtrusiveJavaScriptEnabled的值来开启或关闭客户端验证。启用时还需要包含三个JS引用:

  • /Scripts/ jquery-1.7.1.min.js
  • /Scripts/ jquery.validate.min.js
  • /Scripts/ jquery.validate.unobtrusive.min.js

    当我们启用客户端验证后,要使用起来,最简单的方便是对Model应用验证特性,如Required、Range等。为了演示,我们修改 Appointment 类如下:

public class Appointment 
{
    [Required]
    [StringLength(10, MinimumLength = 3)]
    public string ClientName { get; set; }

    [DataType(DataType.Date)]
    public DateTime Date { get; set; }

    public bool TermsAccepted { get; set; }
}

     这里的验证规则是通过后台指定的。但并不是所有后台使用的验证都有对应的客户端验证,例如 action 中的验证、应用Model级的验证特性和Model的自验证都是没有客户端验证的。

     Tips:使用 MVC 提供的客户端验证的好处:不用写 JavaScript 代码;用户可以即时的看到验证消息,更快地得到反馈,如果用户禁用了JavaScript, MVC 就会走后台验证。

11、Remote 验证实际上就是通过 Ajax 实现的,只是被MVC封装好了,用起来简单多了,也不需要写 JavaScript 代码。示例:

//1、定义验证方法
public JsonResult ValidateDate(string Date) {
    DateTime parsedDate;
    if (!DateTime.TryParse(Date, out parsedDate)) {
        return Json("Please enter a valid date (yyyy/mm/dd)", JsonRequestBehavior.AllowGet);
    }
    else if (DateTime.Now > parsedDate) {
        return Json("Please enter a date in the future", JsonRequestBehavior.AllowGet);
    }
    else {
        return Json(true, JsonRequestBehavior.AllowGet);
    }
}

//2、使用
public class Appointment 
{
    public string ClientName { get; set; }

    [DataType(DataType.Date)]
    [Remote("ValidateDate", "Home")]
    public DateTime Date { get; set; }

    public bool TermsAccepted { get; set; }
}

    效果上和客户端验证差不多,但验证的处理是在 Controller 中的 Action 中发生的。应用 Remote 特性的字段,每次改变它的值都会调用一次后台,所以从某种意义上来说,我们应该尽量避免使用这种验证,除了那种不得不与后台交互的验证,如检查一个用户名是否已经存在。

原文地址:https://www.cnblogs.com/wangwust/p/6392788.html