本节你将为Movie类型增加逻辑验证,以确保任何用户试图使用该应用程序创建或编辑影片时执行验证规则。
DRY(干爽)
ASP.NET MVC的核心原则之一是干爽(“不要自己重复”)。ASP.NET MVC鼓励您只指定一次功能或行为,然后在应用程序中到处使用。这种做法减少了需要编写的代码量,使你的代码编写不容易出错,且更容易维护。
ASP.NET MVC和Entity Framework代码先行为验证提供支持,是干爽原则应用的一个很好的例子。在一个模型的类中以声明方式指定验证规则,在整个应用程序中执行验证规则。
让我们来看看如何在电影应用程序中利用验证支持。
向Movie模型中添加验证规则
首先向Movie类中加入一些验证逻辑。
打开的Movie.cs文件。在文件的顶部添加using语句,引用命名空间:using System.ComponentModel.DataAnnotations;
请注意,命名空间中不包含的System.Web。 DataAnnotations提供了内置的验证属性,你可以对任何类或属性应用。
现在修改Movie类,利用内置的Required
、StringLength,和Range
验证属性。下面的代码是应用属性的例子:
public class Movie { public int ID { get; set; } [Required] public string Name { get; set; } public string Genra { get; set; } [Range(1,100)] public decimal Price { get; set; } public DateTime Date { get; set; } [StringLength(5)] public string Rating { get; set; } }
运行程序后你会再次遇到错误:
支持“MovieDbContext”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库(http://go.microsoft.com/fwlink/?LinkId=238269)。
按上节学习的步骤,先在库管理器控制台中执行add-migration AddDataAnnotationsMig
命令,再执行update-database
命令,查看AddDataAnnotationsMig
文件,其中的Up
方法,可以看到Name
字段不能为空,Rating
属性最大长度为5
。
public override void Up() { AlterColumn("dbo.Movies", "Name", c => c.String(nullable: false)); AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5)); }
验证属性指定应用到模型属性要执行的行为。Required
属性表示属性不能为空,在本示例中,影片名称必须有值。Range
范围属性限制值在指定的范围内。 StringLength属性可让您设定字符串最大长度,以及最小长度(可选)。内建类型(如decimal, int, float, DateTime
)默认情况下,并不需要Required
属性。
代码先行确保应用程序将更改保存到数据库前你指定的模型类的验证规则被执行。例如,下面的代码调用SaveChanges方法时将抛出一个异常,因为不能为空的的片名属性值没有值,以及价格是零(不在有效范围内)。
MovieDbContext db = new MovieDbContext(); Movie movie = new Movie(); movie.Title = ""; movie.Price = 0.0M; db.Movies.Add(movie); db.SaveChanges();
.NET Framework自动执行验证规则,使您的应用程序更加健壮。它可确保您不忘记验证东西,以及不经意间让错误的数据存到数据库中。
ASP.NET MVC中验证出错界面
运行程序,点击“新建”链接,新建一部影片。使用一些无效数据来填充表单,然后点击创建按钮。
请注意,表单自动使用红色边框的突出显示包含无效的数据的文本框,并在每一个旁边提示适当的验证错误消息。错误包括客户端(使用JavaScript和jQuery)和服务器端(如果用户已禁用JavaScript)。
一个真正的好处是,你并不需要改变MoviesController类或者 Create.cshtml视图中的一行代码,就可以实现验证界面。您在本教程前面创建的控制器和视图,自动使用您指定的Movie模型类的属性上的验证属性的验证规则。
您可能已经注意到的Name属性,Required属性没有被执行,直到您提交表单(点击Create按钮),或在输入字段中输入文本并删除它。初始值为空(如创建视图中的字段)且只有required属性,没有其他的验证属性的字段,你可以执行以下操作来触发验证:
1.Tab键进入该字段。
2.输入一些文字。
3.Tab键移出。
4.按Tab切换回进入该字段。
5.删除文本。
6.Tab键移出。
上述顺序将触发所要求的验证,不需要点击“提交”按钮。只要按“提交”按钮,无需进入任何字段,将触发客户端验证。若没有客户端验证错误,则表单数据发送到服务器。您可以通过在HTTP POST方法设置断点或者使用Fiddler工具或IE 9 F12开发人员工具来测试这点。
创建视图和创建方法中如何触发验证
你可能想知道生成的控制器或视图中的代码没有任何更新的情况下验证界面是如何产生的。下一个清单显示的是在MovieController类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])版本的操作方法负责处理post请求。第二个Create的方法(HttpPost版本)调用ModelState.IsValid,以检查是否有任何验证错误。调用该方法将检查任何已应用到对象属性上的验证。如果对象的Create方法验证错误,重新显示表单。如果没有错误,该方法在数据库中保存新的电影。在我们的电影例子中,在客户端验证检测到的错误,表单将不会发送到服务器时,第二个Create方法不会被调用。如果您在您的浏览器禁用了JavaScript,客户端验证被禁用,HTTP POST版本的Create方法调用ModelState.IsValid,以检查是否有任何验证错误。
您可以在HttpPost Create方法中设置一个断点,验证该方法不会被调用,客户端验证发现错误时将不提交表单数据。如果您在您的浏览器禁用了JavaScript,然后提交有错误的表单,断点会命中。不支持JavaScript的情况下,你仍然可以得到充分验证。
请注意,代码是如何使用Html.EditorFor助手为每个Movie属性输出<input>元素的。也注意下 Html.ValidationMessageFor助手。这两个辅助方法,通过控制器传递给视图的模型对象(在本例中是Movie对象)发生作用。它们自动寻找模型上指定的验证属性并显示验证错误信息。
控制器和Create视图模板不知道什么实际的验证规则正在执行或特定的错误消息显示,这种做法非常好。只需要在Movie类里指定验证规则和错误字符串,同样的验证规则会自动应用到编辑视图和任何其他视图模板,您可以创建,编辑您的模型。
如果你想更改的验证逻辑,你可以限定在一处地方(在这个例子中,Movie类),为模型添加验证属性。你不需要担心应用程序的不同部分执行的规则不一致- 所有的验证逻辑将被定义在一个地方,应用在各个地方。这样可以使代码很干净,而且很容易进行维护和改进。这意味着,你会充分履行了DRY原则。
为模型添加格式化信息
打开的Movie.cs的文件,查看的Movie类。 System.ComponentModel.DataAnnotations命名空间中除了内置的验证属性,还提供了格式化属性。下面的代码显示了添加适当的DisplayFormat属性的Date和Price。
[DataType(DataType.Currency)] public decimal Price { get; set; } [DataType(DataType.Date)] public DateTime Date { get; set; }
DataType
属性不是验证属性,它是用来告诉视图引擎如何生成HTML。在上面的例子中,DataType.Date属性显示Date为日期,不包含时间。例如,下面的数据类型属性不验证数据格式:
[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]
上面列出的属性为视图引擎格式化数据提供一些参考(为url提供<a>以及为email提供<a href="mailto:EmailAddress.com">)。您可以使用正则表达式来验证格式化数据。
使用的DataType
属性的另一种方法,你可以显式设置DataFormatString
值。下面的代码显示的日期格式字符串(即“D
”)的发布日期属性。使用该功能,表明你不想把时间作为日期的一部分。
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }
下面的代码将Price属性格式化为货币
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal Price { get; set; }
在下节课程中,我们将回顾应用程序,为自动生成的Details和Delete方法做出一些改进。
译文地址:http://www.cnblogs.com/seawaving/archive/2012/12/06/2806322.html