【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 特性的字段,每次改变它的值都会调用一次后台,所以从某种意义上来说,我们应该尽量避免使用这种验证,除了那种不得不与后台交互的验证,如检查一个用户名是否已经存在。