在这本部分会将验证逻辑添加到Movie
模式,和你会确保验证规则执行任何时候用户试图创建或编辑使用该应用程序的一部电影。
保持事物的干练性
ASP.NET MVC 的核心设计信条之一是 DRY(”Don't Repeat Yourself“,不要重复)。ASP.NET MVC 鼓励你只有一次,指定的功能或行为,然后让它无处不在应用程序中反映。这减少了需要编写的代码量,并使你写更少错误倾向和易于维护的代码。
ASP.NET MVC 和 Entity Framework Code First 中提供的验证支持就是操作中 DRY 原则的很好的例子。您可以在一个地方 (在模型类) 中以声明方式指定验证规则和无处不在应用程序中强制执行的规则。
让我们看看如何您可以利用这种验证支持的在电影中的应用。
向电影模型中添加验证规则
你就开始向Movie
类添加一些验证逻辑。
打开Movie.cs文件。 System.ComponentModel.DataAnnotations
命名空间引用的文件的顶部添加using
语句:
using System.ComponentModel.DataAnnotations;
注意到该命名空间不包含System.Web
。DataAnnotations 提供了一组内置的验证特性,您可以以声明方式适用于任何类或属性。
现在更新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; }
}
运行该应用程序,你又会得到下面的运行的时错误:
自创建数据库,支持 'MovieDBContext' 上下文模型已更改。请考虑使用代码第一次迁移来更新数据库 (http://go.microsoft.com/fwlink/?LinkId=238269).
我们将我们的迁移,以更新 scheam。生成解决方案,然后打开程序包管理器控制台窗口并输入以下命令:
add-migration AddDataAnnotationsMig
update-database
当此命令完成,Visual Studio 打开定义具有指定的名称 (AddDataAnnotationsMig),新的DbMIgration
派生类的类文件并在Up
的方法,你可以看到的代码更新架构约束。Title
和Genre
领域不再是可以为 null (也就是说,您必须输入一个值) 和Rating
字段的最大长度为 5。
验证属性指定您想要在将它们应用于模型属性上实施的行为。 Required
的属性指示的属性必须具有一个值 ;在此示例中,一部电影都必须有Title
、 ReleaseDate
、Genre
和Price
属性值才有效。Range
属性限制对指定范围内的值。StringLength
属性允许您设置一个字符串属性的最大长度和 (可选) 其最小长度。内部类型 (例如decimal, int, float, DateTime
) 默认需要和不需要的Required
属性。
代码首先确保您在一个模型类指定的验证规则执行之前应用程序将更改保存在数据库中。例如,下面的代码在调用SaveChanges
方法时,将引发异常,因为几个需要Movie
属性的值是失踪和价格是零 (即超出有效范围)。
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
具有验证规则会自动执行由.NET 框架有助于使您的应用程序更加健壮。它还确保你不能忘验证的东西,无意中让坏的数据到数据库中。
下面是完整的代码清单的更新的Movie.cs文件:
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace MvcMovie.Models {
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; }
}
public class MovieDBContext : DbContext {
public DbSet<Movie> Movies { get; set; }
}
}
验证错误在 ASP.NET MVC 中的 UI
重新运行应用程序,然后定位到/Movies URL。
单击创建新的链接以添加一部新电影。填写一些无效的值,然后单击创建按钮。
Globalize.parseFloat
。下面的代码演示对要与"FR-FR"文化工作的 ViewsMoviesEdit.cshtml 文件的修改:@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/globalize.js"></script>
<script src="~/Scripts/globalize.culture.fr-FR.js"></script>
<script>
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$(document).ready(function () {
Globalize.culture('fr-FR');
});
</script>
<script>
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Use the Globalization plugin to parse the value
var val = $.global.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
</script>
}
请注意如何窗体已自动用于红色边框的颜色突出显示文本框中包含无效数据,已经发出在每一个适当的验证错误消息。错误强制执行 (使用 JavaScript 和 jQuery) 的客户端和服务器端 (以防用户已禁用 JavaScript)。
真正的好处是你不需要为了使这种验证 UI 更改一行代码在MoviesController
类中或在Create.cshtml视图中。控制器和视图创建早些时候在本教程中,自动捡起你通过使用验证特性上Movie
模式类的属性指定的验证规则。
你可能已经注意到的属性Title
和Genre
,所需的属性是不强制执行直到你提交表单 (击中了创建按钮),或在输入字段中输入文本并删除它。字段是最初为空 (例如创建视图字段) 并具有唯一必需的属性并没有其他的验证属性,您可以执行以下操作来触发验证:
- 到该字段的选项卡。
- 输入一些文本。
- 选项卡了。
- 按 tab 键返回该字段。
- 删除的文本。
- 选项卡了。
上面的顺序将没有击中提交按钮触发必需的验证。简单地击打而无需输入任何字段的提交按钮,将会触发客户端验证。有没有客户端验证错误之前表单数据不会发送到服务器。您可以测试这一个破发点置于 HTTP Post 方法或用提琴手工具或 IE 9 F12 开发人员工具.
如何验证发生在创建查看和创建操作方法
您可能想知道如何验证用户界面生成没有任何更新的控制器或视图中的代码。下一个清单显示MovieController
类中的方法 Create
的外观。他们从早些时候在本教程中创建的方式不变。
//
// 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);
}
第一次 (HTTP GET)Create
操作方法显示初始创建窗体。第二个 ([HttpPost]
) 版本处理窗体发布。第二种Create
方法 ( HttpPost
版本) 调用 ModelState.IsValid
来检查电影有否任何验证错误。调用此方法的计算结果已应用于该对象的任何验证属性。如果对象具有验证错误,则Create
方法重新显示窗体。如果没有错误,该方法在数据库中保存的新电影。在我们电影的例子,我们使用的,检测到 ; 客户端上的验证错误时不向服务器发送窗体第二Create
永远不会调用方法。如果您在您的浏览器中禁用 JavaScript,禁用客户端验证和Create
HTTP POST 方法调用ModelState.IsValid
来检查电影有否任何验证错误。
您可以在HttpPost Create
方法中设置一个断点,并验证永远不会调用该方法,客户端验证不会提交表单数据时检测到验证错误。如果您在您的浏览器中禁用 JavaScript,然后提交具有错误的窗体,将命中破发点。你仍然得到了充分验证没有 JavaScript。下面的图像演示如何禁用 JavaScript 在 Internet explorer 中。
下面的图像演示如何在火狐浏览器中禁用 JavaScript。
下面的图像演示如何禁用 JavaScript 的 Chrome 浏览器。
下面是您搭建早些时候在本教程中的Create.cshtml视图模板。如上所示两个操作方法使用显示初始窗体,并在出现错误时重新显示它。
@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>
请注意代码如何使用Html.EditorFor
帮助器输出的每个Movie
属性的<input>
元素。此帮助器旁边是对Html.ValidationMessageFor
帮助器方法的调用。这两个帮助器方法处理由控制器传递到视图 (在本例中,是一个Movie
对象) 的模型对象。他们会自动查找指定的模型和显示的错误消息,作为适当的验证属性。
关于这种方法真的很好的是控制器既创建视图模板知道任何有关实施的实际验证规则或显示的特定错误消息。在Movie
类仅指定了验证规则和错误字符串。这些相同的验证规则将自动应用到编辑视图和任何其他视图模板可以创建,编辑您的模型。
如果你想要在以后更改的验证逻辑,你可以在一个地方通过将验证属性添加到模型 (在此示例中,movie
课)。你不必担心不符合规则 》 如何强制执行的应用程序的不同部分 — — 所有的验证逻辑会在一个地方定义和使用无处不在。这使代码很干净,并使它易于维护和发展。它意味着你会充分尊重 DRY 原则。
添加格式电影模型
打开Movie.cs文件并检查Movie
课。 System.ComponentModel.DataAnnotations
命名空间提供了内置的验证特性集的格式属性。我们已应用一个DataType
的枚举值的发布日期和价格字段。下面的代码演示的ReleaseDate
和Price
属性与相应的DisplayFormat
属性。
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
DataType
属性不是验证特性,它们被用来告诉视图引擎如何呈现的 HTML。在上面的示例中, DataType.Date
属性显示电影日期作为仅限于日期没有时间。例如,下面的DataType
属性不需要验证的数据的格式:
[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]
上面列出的属性仅提供视图引擎来设置数据的格式的提示 (如提供属性和 < > url 的和 < href="mailto:EmailAddress.com"> 电子邮件。可以使用正则表达式属性来验证数据的格式。
使用DataType
属性的替代方法,您可以显式设置一个DataFormatString
值。下面的代码演示了具有一个日期格式字符串的释放日期属性 (namely,"d")。你会使用这指定作为一部分的发行日期时间不要。
[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]
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; }
}
运行该应用程序,然后浏览到Movies
控制器。很好地格式化的发布日期和价格。下面的图像显示的发布日期和价格使用"FR-FR"作为文化。
下面的图像显示了相同的数据,显示与默认区域性 (美国英语)。
在本系列的下一部分,我们会检讨中应用,作了一些改进的自动生成的Details
和 Delete
方法。