【译】ASP.NET MVC 5 教程 - 10:添加验证
原文:【译】ASP.NET MVC 5 教程 - 10:添加验证
在本节中,我们将为Movie模型添加验证逻辑,并确认验证规则在用户试图使用程序创建和编辑电影时有效。
DRY 原则
ASP.NET MVC 的一个核心原则是DRY(Don't Repeat Yourself - 不做重复的事情)。ASP.NET MVC 鼓励你一次性的指定功能或行为,然后应用程序的其它地方通过映射得到它,这样一来就减少了大量的代码,从而减少了出错误的可能性,并且更易于维护。
ASP.NET MVC 和 Entity Framework Code First 提供的验证能是 DRY 原则的不错的实践。你可以在一处(在模型类中)定义验证规则,从而在应用程序中的所有地方都可以使用这个规则。
接下来让我们看看如何在现在的Movie 中添加高级的验证规则吧。
为模型添加验证规则
现在我们开始为Movie类添加一些验证规则。
打开文件 Movie.cs,注意命名空间 System.ComponentModel.DataAnnotations 并不包含 System.Web。DataAnnotations 提供了内置的验证特性,你可以将它们用在任何类或属性中(它还包含了像DataType这样的格式化的特性,它们不参与任何验证)。
为Movie类添加一些内置的验证规则,修改后的代码如下:
public class Movie
{
public int ID { get; set; } [Required]
[StringLength(, MinimumLength = )]
public string Title { get; set; } [Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; } [Required]
public string Genre { get; set; } [Range(, )]
[DataType(DataType.Currency)]
public decimal Price { get; set; } [StringLength()]
[Required]
public string Rating { get; set; }
}
使用数据迁移来更新数据库结构。编译解决方案,然后打开“程序包管理器控制台”窗口,执行下面的命令:
add-migration DataAnnotations
update-database
当这两个命令执行完成之后,Visual Studio 为我们创建了 DataAnnotations 类,它继承自 DbMigration。打开文件,在它的Up方法中,你会看到升级结构的代码:
public override void Up()
{
AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false, maxLength: ));
AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false));
AlterColumn("dbo.Movies", "Rating", c => c.String(nullable: false, maxLength: ));
}
从代码中可以看出,Title、Genre和Rating三个字段不再允许为空(这意味着你必须输入一个值)。Rating 字段的最大长度为5,Title 的最大长度为60,最小长度为3。
Code First 确保在保存到数据库的时候使用你指定的规则对数据进行验证,例如,下面的代码在调用SaveChanges的时候会抛出一个错误:
MovieDBContext db = new MovieDBContext(); Movie movie = new Movie();
movie.Title = "Gone with the Wind"; db.Movies.Add(movie);
db.SaveChanges(); // <= 会引发一个服务器段的错误,因为movie的必须的字段没有赋值
验证规则在保存的时候自动生效使得程序变得更为健壮,它可以在是你忘记去验证,而在不经意间阻止不合法的进入数据库。
ASP.NET MVC 客户端验证
运行应用程序,浏览地址 /movies,点击“Create New”链接添加一个电影。如果我们在输入过程中出现一些不合法的数据,客户端将会显示一些错误,这是通过 jQuery 客户端验证来实现的。下面是一些错误信息:
当出现错误的时候,文本框会被加上红色的边框,并且会显示一段错误描述信息。这些错误信息可以在客户端(使用Javascript 和 jQuery)和服务器(当客户端Javascript无效时)段生效。
一个真正的好处是,你不需要在MoviesController 或 Create.cshtml 中修改一行代码来启用客户端验证,控制器和视图会根据我们之前定义在Movie类中的验证特性自动选择验证规则。
表单数据出现错误的时候不会被提交到服务器端。
验证是如何工作的
你可能会觉得奇怪,客户端验证是如何在没有修改控制器或视图代码的情况下生成的。下面的代码显示了MovieController的Create方法,它和我们前面的教程中的Create代码一样,并没有经过修改:
//
// GET: /Movies/Create
public ActionResult Create()
{
return View();
} //
// POST: /Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index");
} return View(movie);
}
第一个Create方法显示一个表单,第二个Create方法用来处理POST请求提交的表单数据。第二个Create方法调用ModelState.IsValid来检查movie数据是否存在验证错误,调用这个方法来检查验证规则,如果存在错误,Create 方法将会重新显示这个表单,如果没有,则会将Movie数据保存到数据库。在我们的例子中,当验证出现错误的时候表单不会提交到服务器,第二个Create方法将不会调用。如果你禁用了Javascript客户端验证,第二个Create方法则会调用ModelState.IsValid对数据进行检查。
你可以通过在HttpPost Create 方法中添加断点来监视是否被调用。当客户端出现错误的时候表单将不会提交,如果我们禁用客户端的Javascript,表单将错误的数据提交到服务器,断点将会跟踪到。下面我们介绍一下如何在IE和Google浏览器中禁用Javascript。
在 IE 中禁用Javascript
打开Internet选项,在安全选项中选中“本地Intranet”,点击“自定义级别”按钮:


在火狐(FireFox)中禁用Javascript:

在Google Chrome 中禁用Javascript:
下面是 Create.cshtml 视图的代码,它被控制器中的Create方法用来显示初始的form表单,或在发生错误时重新显示带错误信息的表单数据。
@model MvcMovie.Models.Movie
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset class="form-horizontal">
<legend>Movie</legend>
<div class="control-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title, null, new { @class = "help-inline" })
</div>
</div>
<div class="control-group">
@Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.ReleaseDate)
@Html.ValidationMessageFor(model => model.ReleaseDate, null, new { @class = "help-inline" })
</div>
</div>
<div class="control-group">
@Html.LabelFor(model => model.Genre, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Genre)
@Html.ValidationMessageFor(model => model.Genre, null, new { @class = "help-inline" })
</div>
</div>
<div class="control-group">
@Html.LabelFor(model => model.Price, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price, null, new { @class = "help-inline" })
</div>
</div>
<div class="control-group">
@Html.LabelFor(model => model.Rating, new { @class = "control-label" })
<div class="controls">
@Html.EditorFor(model => model.Rating)
@Html.ValidationMessageFor(model => model.Rating, null, new { @class = "help-inline" })
</div>
</div>
<div class="form-actions no-color">
<input type="submit" value="Create" class="btn" />
</div>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
模型格式化输出
打开文件Movie.cs,检查Movie类,System.ComponentModel.DataAnnotations 命名空间除了一套内置的验证特性外,还提供了格式化特性。我们已经在ReleaseDate 和Price字段用到过DataType枚举,下面的代码展示了ReleaseDate和Price属性中使用的DisplayFormat特性:
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; } [Range(, )]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
DataType特性不是验证特性,他们用来告诉试图引擎如何绘制HTML。在上面的例子中,DataType.Date 特性使ReleaseDate显示的时候只显示日期部分,而不显示时间。下面的DataType特性不验证数据的格式:
[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]
这些特性只为试图引擎格式化显示数据时提供建议。你可以使用RegularExpression 特性连验证数据的格式。
除了使用现成的DataType 格式化特性之外,你还可以明确指定 DataFormatString 值。下面的代码展示了ReleaseDate属性使用格式化字符串的情况,你可以使用它来不显示ReleaseDate日期的时间部分:
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }
下面的代码将Price显示为货币的格式:
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal Price { get; set; }
完整的Movie类代码如下:
public class Movie
{
public int ID { get; set; } [Required]
[StringLength(, MinimumLength = )]
public string Title { get; set; } [Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; } [Required]
public string Genre { get; set; } [Range(, )]
[DataType(DataType.Currency)]
public decimal Price { get; set; } [StringLength()]
[Required]
public string Rating { get; set; }
}
面的代码展示了如何将特性合并在一行显示:
public class Movie
{
public int ID { get; set; } [Required, StringLength(, MinimumLength = )]
public string Title { get; set; } [Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; } [Required]
public string Genre { get; set; } [Range(, ), DataType(DataType.Currency)]
public decimal Price { get; set; } [Required, StringLength()]
public string Rating { get; set; }
}
在本系列的下一部分,我们将回顾整个应用程序,并对自动生成的Details 和Delete 方法做一些改进。
【译】ASP.NET MVC 5 教程 - 10:添加验证的更多相关文章
- 【译】ASP.NET MVC 5 教程 - 9:添加新字段
原文:[译]ASP.NET MVC 5 教程 - 9:添加新字段 在本节中,我们将使用Entity Framework Code First 数据迁移功能将模型类的改变应用到数据库中. 默认情况下,当 ...
- 【译】ASP.NET MVC 5 教程 - 4:添加模型
原文:[译]ASP.NET MVC 5 教程 - 4:添加模型 在本节中,我们将添加一些管理电影数据库的类,这些类在ASP.NET MVC 应用程序中扮演“Model”的角色. 我们将使用.NET F ...
- 【译】ASP.NET MVC 5 教程 - 3:添加视图
原文:[译]ASP.NET MVC 5 教程 - 3:添加视图 在本节内容中,我们将修改HelloWorldController类,使用视图模板来干净利索的封装生成HTML响应客户端的过程. 您将创建 ...
- 【译】ASP.NET MVC 5 教程 - 2:添加控制器
原文:[译]ASP.NET MVC 5 教程 - 2:添加控制器 MVC 表示 模型-视图-控制器.MVC 是一种用于开发应用程序的模式,具备良好架构,可测试和易于维护.基于 MVC 应用程序中包含: ...
- 【译】ASP.NET MVC 5 教程 - 11:Details 和 Delete 方法详解
原文:[译]ASP.NET MVC 5 教程 - 11:Details 和 Delete 方法详解 在教程的这一部分,我们将研究一下自动生成的 Details 和Delete 方法. Details ...
- 【译】ASP.NET MVC 5 教程 - 8:搜索查询
原文:[译]ASP.NET MVC 5 教程 - 8:搜索查询 添加一个搜索的方法和搜索的视图 在本节中,我们为 Index 方法添加查询功能,使我们能够根据电影的题材或名称进行查找. 修改 Inde ...
- 【译】ASP.NET MVC 5 教程 - 7:Edit方法和Edit视图详解
原文:[译]ASP.NET MVC 5 教程 - 7:Edit方法和Edit视图详解 在本节中,我们继续研究生成的Edit方法和视图.但在研究之前,我们先将 release date 弄得好看一点.打 ...
- 【译】ASP.NET MVC 5 教程 - 6:通过控制器访问模型的数据
原文:[译]ASP.NET MVC 5 教程 - 6:通过控制器访问模型的数据 在本节中,你将新建一个MoviesController 类,并编写获取电影数据的代码,使用视图模板将数据展示在浏览器中. ...
- 【译】ASP.NET MVC 5 教程 - 5:使用 SQL 服务器 LocalDB 创建连接字符串
原文:[译]ASP.NET MVC 5 教程 - 5:使用 SQL 服务器 LocalDB 创建连接字符串 在上一节中,我们创建了MovieDBContext 类来连接数据库.处理Movie 对象和数 ...
随机推荐
- 正则表达式概述与JAVA中正则表达式的应用
编程或者电脑使用过程中,经常需要对字符串进行 匹配,查找,替换,判断.如果单纯用代码 if () ,whlie 什么的进行比较复杂麻烦.正则表达式是一种强大灵活的文本处理工具,专门对字符串进行匹配,查 ...
- Qt Quick鼠标事件处理、键盘、计时器
在<Qt Quick 事件处理之信号与槽>中介绍了 QML 中怎样使用内建类型的信号以及怎样自己定义信号,这次我们来看看怎样处理鼠标.键盘.定时器等事件.这些时间在处理时,一般是通过信号来 ...
- MapReduce整体架构分析
继前段时间分析Redis源代码一段时间之后.我即将開始接下来的一段技术学习的征程.研究的技术就是当前很火热的Hadoop,可是一个Hadoop生态圈是很庞大的.所以首先我的打算是挑选当中的一部分模块, ...
- 自己总结的ruby on rails 查询方法
闲来无事,结合以前的代码,总结了ruby on rails的查询方法,方便自己以后查看,也方便后来人,如下,欢迎批评指正 1::simpleDB modules = find(:all, :condi ...
- C# 数据访问编码需要遵循的几个规范
一,链接打开之后必须关闭,否则会占用系统空间 SqlConnection conn=new SqlConnection(CONNECTIONSTRING); conn.open(); conn.clo ...
- .net生成Excel,并下载
生成Excel的方式有很多种,这里记录两个最简单的: 1.将数据保存为html,然后输出到客户端,保存为Excel文件: 2.通过\t\n生成字符串,然后输出到客户端,保存为Excel. 以上两者的原 ...
- underscore.js 源码
underscore.js 源码 underscore]JavaScript 中如何判断两个元素是否 "相同" Why underscore 最近开始看 underscore.js ...
- 终于懂了:WM_PAINT 与 WM_ERASEBKGND(三种情况:用户操作,UpdateWindow,InvalidateRect产生的效果并不相同),并且用Delphi代码验证 good
一直对这两个消息的关系不是太了解,借重新深刻学习windows编程的机会研究一番. 1)当窗口从无效变为有效时,比方将部分覆盖的窗口恢复时会重绘窗口时:程序首先会通过发送其他消息调用DefWindow ...
- hdu 4710 Balls Rearrangement 数论
这个公倍数以后是循环的很容易找出来,然后循环以内的计算是打表找的规律,规律比较难表述,自己看代码吧.. #include <iostream> #include <cstdio> ...
- pig对null的处理(实际,对空文本处理为两种取值null或‘’)
pig对文本null的处理非常特殊.会处理成两种null,还会处理成''这样的空值. 比方,读name,age,sex日志信息.name取值处理,假设记录为".,,"这样,会将na ...