演练2-6:为模型添加验证规则
坚持DRY原则
ASP.NET MVC中的一个设计原则是DRY(“Don't Repeat Yourself”)。相同功能或行为的代码只写一遍,然后在应用程序的任何地方都可以引用。这样减少了代码数量,降低使代码出错可能性,并且更容易维护。
ASP.NET MVC和Entity Framework Code First中的验证规则设置,就是DRY的一个很好的实践。你可以在模型中声明验证规则,然后这个验证规则就可以在应用程序的各个地方使用。
接下来我们将在电影网站中使用这个验证规则。
1.在Movie模型中添加验证规则
修改模型代码,使用Required、StringLength、Range验证属性。
public class Movie { public int ID { get; set; } [Required]
public string Title { get; set; } [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Required] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [StringLength(5)] public string Rating { get; set; } }
运行程序后,得到如下错误。
The model backing the 'MovieDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
我们需要进行数据迁移,打开程序包管理器控制台。
add-migration AddDataAnnotationsMig
update-database
在Up方法中,可以看到模式约束代码。
public override void Up() { AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false)); AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false)); AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5)); }
- Required,必须有值,不能为空。Title、ReleaseDate、Genre、Price都不能为空。值类型(如decimal, int , float, DateTime)是默认为不能为空的。
- Range,设定数值范围,如Range(1,100)。
- StringLength(5),设定字符串长度。
MovieDBContext db = new MovieDBContext(); Movie movie = new Movie(); movie.Title = "Gone with the Wind"; movie.Price = 0.0M; db.Movies.Add(movie); db.SaveChanges(); // <= Will throw server side validation exception
分析出错原因。
2.验证UI中可能发生的错误
我们不必在控制器或视图中添加任何代码,去验证字段合法性,控制器和视图会自动获取验证规则。
// // GET: /Movies/Create public ActionResult Create() { return View(); } // // POST: /Movies/Create [HttpPost] public ActionResult Create(Movie movie) { if (ModelState.IsValid) { db.Movies.Add(movie); db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Create"; } <h2>Create</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Movie</legend> <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> <div class="editor-label"> @Html.LabelFor(model => model.ReleaseDate) </div> <div class="editor-field"> @Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate) </div> <div class="editor-label"> @Html.LabelFor(model => model.Genre) </div> <div class="editor-field"> @Html.EditorFor(model => model.Genre) @Html.ValidationMessageFor(model => model.Genre) </div> <div class="editor-label"> @Html.LabelFor(model => model.Price) </div> <div class="editor-field"> @Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price) </div> <div class="editor-label"> @Html.LabelFor(model => model.Rating) </div> <div class="editor-field"> @Html.EditorFor(model => model.Rating) @Html.ValidationMessageFor(model => model.Rating) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div>
3.在模型中添加格式
打开Movie.cs文件,System.ComponentModel.DataAnnotations命名空间提供了属性格式。DataType属性并不是验证属性,它们用来告诉视图引擎怎么去渲染HTML,比如DataType.Date只显示日期,并不包括时间。
[DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [DataType(DataType.Currency)] public decimal Price { get; set; }
[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]
这些属性知识提供了格式化的数据(<a href="mailto:EmailAddress.com">)。如果需要格式化验证数据,可以使用正则表达式RegularExpressions。
也可以显式地使用DataFormatString值,如下所示。
[DisplayFormat(DataFormatString = "{0:d}")] public DateTime ReleaseDate { get; set; }
日期中不需要时间。
[DisplayFormat(DataFormatString = "{0:c}")] public decimal Price { get; set; }
价格为货币。
public class Movie { public int ID { get; set; } [Required] public string Title { get; set; } [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Required] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [StringLength(5)] public string Rating { get; set; } }
运行程序,查看功能。