在本节中将会给Movie模型添加验证逻辑。而且确保这些验证规则在用户建立或编辑电影时被执行。html
ASP.NET MVC 的核心设计信条之一是DRY: "不要重复本身(DRY --Don’t Repeat Yourself)"。ASP.NET MVC鼓励您指定功能或者行为,只作一次,而后将它应用到应用程序的各个地方。这能够减小您须要编写的代码量,并减小代码出错率,易于代码维护。html5
给ASP.NET MVC 和 Entity Framework Code First 提供验证支持是 DRY 信条的一次伟大实践。您能够在一个地方 (模型类) 中以声明的方式指定验证规则,这个规则会在应用程序中的任何地方执行。jquery
让咱们看看您如何在本电影应用程序中,使用此验证支持。web
您将首先向Movie
类添加一些验证逻辑。chrome
打开Movie.cs 文件,注意到System.Web 命名空间并未包含System.ComponentModel.DataAnnotations. DataAnnotations提供了一组内置的严重属性,可供您应用于类、属性。(DataAnnotations也包含一个DataType属性,来帮助格式化的办法来校验)数据库
更新Movie
类,以利用内置的Required
、 StringLength
, RegularExpression和Range
验证属性。如下面的代码为例,以应用验证属性。express
public class Movie { public int ID { get; set; } [StringLength(60, MinimumLength = 3)] public string Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateTime ReleaseDate { get; set; } [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")] [Required] [StringLength(30)] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")] [StringLength(5)] public string Rating { get; set; } }
在StringLength属性设置字符串的最大长度,它会在数据库上设置此限制,所以的数据库schema将发生变化。右键单击电影表, 在服务器资源管理器(Server explorer),而后单击打开表定义(Open Table Definition):浏览器
在上面的图片中,你能够看到全部的字符串字段被设置为了NVARCHAR (MAX)数据类型. 咱们将使用迁移来更新架构。生成解决方案,而后打开软件包管理器控制台(the Package Manager Console ),输入以下命令:服务器
add-migration DataAnnotations
update-database架构
当这个命令完成后,Visual Studio将打开类代码文件,它定义了新DbMIgration派生类(DataAnnotations),你能够在Up方法看到更新架构约束代码以下所示:
public override void Up() { AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60)); AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30)); AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5)); }
该流派(Genre)字段再也不可为Null(也就是说,你必须输入一个值)。该评级(Rating)字段最大长度为5, 标题的最大长度为60。标题(Title )和价格 (Price)的范围的最小长度并无更改。
请在数据库中,检查电影表的schema:
该字符串字段显示新的长度限制和流派字段(Genre)不能再为空。
验证属性指明您想要应用到模型属性的行为。Required 和MinimumLength属性指出某一属性不可为空,但没有什么可以阻止用户输入空格来验证。该RegularExpression属性是用来限制哪些字符能够输入。在上面的代码中,流派(Genre)和等级(Rating)只能使用字母(空格,数字和特殊字符是不容许的)。该范围(Range )属性约束的值在一个指定范围内。在StringLength 属性容许您设置一个字符串属性的最大长度,以及最小长度(可选的)。值类型(decimal, int, float, DateTime)有固有必需设置的,不须要的Required属性。
Code First确保你的模型在指定class上在验证规则强制执行以前应用程序将变动储存在数据库中。例如,下面的代码将抛出一个DbEntityValidationException 异常时,调用SaveChanges方法时,由于几个必要的Movie属性缺乏:
MovieDBContext db = new MovieDBContext(); Movie movie = new Movie(); movie.Title = "Gone with the Wind"; db.Movies.Add(movie); db.SaveChanges(); // <= Will throw server side validation exception
上面的代码会抛出如下异常:
Validation failed for one or more entities. 参阅 'EntityValidationErrors' 属性得到更多信息.
具备经过.NET Framework会自动强制执行的验证规则, 有助于使你的应用程序更加健壮。它还确保能够不会忘记验证的东西,即在不经意间不会让坏的数据写入数据库。
从新运行应用程序,浏览 /Movies的 URL。
单击Create New连接,来添加一部新电影。在窗体中填写一些无效值,而后单击Create按钮。
如同jQuery的客户端验证来检测到错误时,它会显示一个错误消息。
注意,为了使jQuery支持使用逗号的非英语区域的验证 ,须要设置逗号(",")来表示小数点,如本教程前面所述, 你须引入NuGet globalize。请注意,表单在每个相应的验证错误消息旁边,已经自动使用红色边框的颜色突出显示文本框指明无效数据。这些错误是强制执行了客户端端(使用JavaScript和jQuery)和服务器端(若是用户禁用了JavaScript)。
一个真正的好处是,你并不须要更改MoviesController类或Create.cshtml视图中的一行代码,来启用此验证的用户界面。您在前面教程所建立的控制器和视图会自动启用,使用验证指明的Movie model类的属性。使用Edit行为方法,一样的验证方法也彻底适用。直到没有任何客户端验证错误的表单数据,才会被发送回服务器。您能够经过在HTTP POST方法,用一个断点来验证这一点; 或经过使用fiddler tool,或者IE浏览器F12 developer tools。
您可能很想知道验证用户界面在没有更新控制器或视图代码的状况下是如何生成的。下面列出了MovieController
类中的Create
方法。它们是以前教程中自动生成的,并无修改。
public ActionResult Create() { return View(); } // POST: /Movies/Create // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie) { if (ModelState.IsValid) { db.Movies.Add(movie); db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
第一种(HTTP GET)Create
方法用来显示初始的建立form。第二个 ([HttpPost]
) 方法处理form的请求。第二种Create
方法 (HttpPost
版本) 调用 ModelState.IsValid
来检查是否有任何的Movie验证错误。调用此方法将验证对象上全部应用了验证约束的属性。若是对象含有验证错误,则Create
方法会从新显示初始的form。若是没有任何错误,方法将保存信息到数据库。在咱们的电影示例中,咱们使用了验证,当客户端检测到错误时,form不会被post到服务器;因此第二个Create方法永远不会被调用。若是您在浏览器中禁用了 JavaScript,客户端验证也会被禁用,HTTP POST Create
方法会调用 ModelState.IsValid来检查影片是否含有任何验证错误。
您能够在HttpPost Create
方法中设置一个断点,当客户端验证检测到错误时,不会post form数据,因此永远不会调用该方法。若是您在浏览器中禁用 JavaScript,而后提交具备错误信息的form,断点将会命中。您仍然获得充分的验证,即便在没有 JavaScript的状况下。
下图显示了如何禁用 Internet Explorer 中的 JavaScript。
下图显示了如何在火狐浏览器中禁用 JavaScript。
下图显示了如何在 Chrome 浏览器中禁用 JavaScript。
下面是框架代码在以前的教程中生成的Create.cshtml视图模板。它用来为以上两个操做方法来显示初始的form,同时在验证出错时来从新显示视图。
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Movie</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div> @*Fields removed for brevity.*@ <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
请注意,代码如何使用Html.EditorFor
helper 输出为Movie
中的每一个属性的<input>
元素。此Helper旁边是对Html.ValidationMessageFor
方法的调用。这两个Helper方法将处理由控制器传递到视图的模型对象(在这里是,Movie
对象)。它们会自动查找模型中指定的验证属性,并显示适当的错误消息。
若是您想要在后面更改验证逻辑,您能够作在一个地方,将验证信息添加到模型上。 (此示例中,是movie
类)。您没必要担忧不符合规则 ,验证逻辑会在应用程序的不一样部分执行――在一个地方定义验证逻辑将会被使用到各个地方。这使代码很是干净,并使它易于维护和扩展。它意味着您会彻底遵照DRY原则。
打开Movie.cs文件并检查Movie类。在System.ComponentModel.DataAnnotations命名空间提供的格式化(formatting)属性,除了内置的一套验证的属性。咱们已经应用了的DataType枚举值的ReleaseDate和Price 字段。下面的代码显示了ReleaseDate和Price 用适当的的DataType属性。
[DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [DataType(DataType.Currency)] public decimal Price { get; set; }
该DataType属性只提供提示的视图引擎对数据进行格式化(与相应的属性,如<a>取代的URL及 <a href="mailto:EmailAddress.com">取代电子邮件。您可使用RegularExpression的属性来验证数据格式。DataType属性用于指定一个比数据库内部类型更加具体的一种数据类型,但它们不是验证属性。在这种状况下,咱们只须要保留的日期跟踪,而不是日期和时间。该枚举的DataType提供了多种数据类型,如Date, Time, PhoneNumber, Currency, EmailAddress 和其余更多的。该的DataType 的属性也可使应用程序来自动提供特定类型的功能。例如,一个mailto:连接能够DataType.EmailAddress建立和日期选择器能够在支持HTML5的浏览器提供的DataType.Date。该数据类型属性发出的HTML5data-(发音读数据破折号)属性与HTML5的浏览器能够理解。 该DataType 属性不提供任何验证。
DataType.Date并未指定显示的日期格式。默认状况下,根据基于服务器的的CultureInfo预设格式显示数据字段。
该DisplayFormat的属性是用来显式地指定日期格式的:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateTime EnrollmentDate { get; set; }
该ApplyFormatInEditMode设置指定了当值进行编辑显示在一个文本框中,格式化亦应适用。 (您可能不但愿这样的某些字段 - 例如货币值,你可能不但愿在编辑文本框中出现货币符号。)
你能够单独使用DisplayFormat属性;但和DataType属性一块儿,一般是一个好主意。该DataType 属性传递数据的语义,而不是如何呈现它在屏幕上,并具备如下的优势,不带DisplayFormat的:
・ 浏览器可使HTML5的功能(例如显示一个日历控件,在区域设置相应的货币符号,电子邮件中的连接,等等)。
・ 默认状况下,浏览器就会使用基于语言环境(locale)的正确格式呈现数据。
・ 在的DataType属性可使MVC选择合适的字段模板以呈现数据(若是自己所使用的的DisplayFormat使用字符串模板)。欲了解更多信息,请参阅see Brad Wilson's的ASP.NET MVC 2 Templates。 (虽然写的MVC2,本文仍然适用于ASP.NET MVC 5的当前版本。)
若是你使用了的DataType的属性具备一个日期字段,你也必须指明,以确保字段正确地呈现Chrome浏览器中的DisplayFormat属性。欲了解更多信息,请参阅this StackOverflow thread。
注:jQuery的验证不与Range属性和DateTime的同时工做。例如,下面的代码老是显示一个客户端验证错误,即便当日期是在指定的范围内:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
你可能会禁用jQuery的日期校验,而使用带有的Range属性DateTime。这一般不是一个好的作法,在你的模型里,编译器很难肯定日期,因此使用Range属性和DateTime效果很差。
下面的代码显示在同一行合并属性:
public class Movie { public int ID { get; set; } [Required,StringLength(60, MinimumLength = 3)] public string Title { get; set; } [Display(Name = "Release Date"),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; } [Required,StringLength(5)] public string Rating { get; set; } }
在教程的下一部分,咱们先会看看代码,而后再改进一下自动生成的Details
和 Delete
方法。有了本节介绍的内容,相信你们已经掌握了给数据模型添加校验器的方法。后面你们在进行MVC开发时,一方面能够运用本节知识,一方面也能够借助一些开发工具。ComponentOne Studio ASP.NET MVC 是一款针对 MVC 平台的控件包,能提供从桌面到移动设备的用户体验。