[译]为模型添加验证 —— ASP.NET MVC3 电影示例教程之八

asp.net mvc3教程

ASP.NET MVC3教程

ASP.NET MVC3 电影示例系列:共九篇  [文章列表]

这里的文章是ASP.NET官网的教程,M.C.在这里做翻译而已,才疏学浅,翻译错误的地方,请指正,原文地址:Adding Validation to the Model(C#)

在本节中你将向Movie模型添加验证逻辑,并且你将确认在任何时候用户尝试在应用程序中创建或编辑,验证逻辑都已经被执行。

保持事情的DRY(Don't Repeat Yourself)

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命名空间的using语句引用。

using System.ComponentModel.DataAnnotations;

 该命名空间是.NET Framework的一部分。它提供了一个内置的验证特性集合,你可以应用到任何类或属性的定义中。

public class Movie
{
   
public int ID { get; set; }

   
[Required(ErrorMessage = "Title is required")]
   
public string Title { get; set; }

   
[Required(ErrorMessage = "Date is required")]
   
public DateTime ReleaseDate { get; set; }

   
[Required(ErrorMessage = "Genre must be specified")]
   
public string Genre { get; set; }

   
[Required(ErrorMessage = "Price Required")]
   
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
   
public decimal Price { get; set; }

   
[StringLength(5)]
   
public string Rating { get; set; }
}

验证特性为那些你想在应用特性的模型属性上执行验证的属性指定行为。Required特性指明属性必须要有值;在这个示例中,若要通过验证moive的Title,ReleaseDate,Genre,和Price属性必须要有值。Range特性要求值必须在给定的范围内。StringLength特性让你可以为一个字符串属性设置允许的最大长度,还可以可选的设置最短长度。

Code First 会保证在将数据提交到数据库中之前,你为模型类指定的验证规则已被有效执行。举例来说,下面的代码中当SaveChanges方法被调用的时候将会抛出异常,因为Movie中必填的属性没有值并且price也是0(超出了有效范围)。

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 validation exception(将抛出验证异常

有了.NET Framework的验证规则自动执行校验功能的帮助,将使你的应用程序更加的强健。这也能帮你确认你不会忘掉在必要的时候做校验或在非有意的情况下将错误的数据提交到数据库中。

下面是更新后的Movie.cs文件的完整代码:

using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
   
public class Movie
   
{
       
public int ID { get; set; }

       
[Required(ErrorMessage = "Title is required")]
       
public string Title { get; set; }

       
[Required(ErrorMessage = "Date is required")]
       
public DateTime ReleaseDate { get; set; }

       
[Required(ErrorMessage = "Genre must be specified")]
       
public string Genre { get; set; }

       
[Required(ErrorMessage = "Price Required")]
       
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
       
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错误验证

重新运行应用程序并将URL导航到/Movies。

点击创建电影(Create Movie)链接添加一部新电影 。在表单中填写好一些无效的数据后点击创建(Create)按钮。

asp.net mvc3教程:在ui上验证表单输入

注意到表单将会自动为包含非法数据的文本框设置背景色来高亮显示,并在每个非法的文本框之后出现适当的验证错误信息。错误信息与你在为Movie类注释时指定的信息一致1。错误将在客户端(使用JavaScript)和服务端(用户禁用JavaScript的情况下)。

一个看得到的好处是你不需要为了启用UI验证在MoviesController类中或在Create.cshtml视图中修改一行代码。你在本教程之前创建的控制器和视图将自动获得你在Movie模型类中使用特性指定的验证规则。

验证在Create视图和Create 行为方法中是如何触发

你也许想知道在控制类和视图中没有做任何修改的情况下,是如何生成验证UI的。下面显示的是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);
}

第一个行为方法显示初始创建表单。第二个处理Post的表单。第二个Create方法调用ModelState.IsValid来检查电影是否含有验证错误。调用这个方法计算应用到对象上的所有验证特性。如果对象包含验证错误,Create方法会重新显示表单。如果没有错误,方法将心电影保存到数据库中。

下面是你在本教程之前搭建的Create.cshtml试图模板。它被上述行为方法用来显示初始表单和在有错误的时候重新显示表单。

@model MvcMovie.Models.Movie
@{
    ViewBag.Title = "Create";
}
<h2>
    Create
</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></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 对象)。自动搜寻在模型上指定的验证特性并将错误以适当的方式显示出来。

这个方法的真正好处是,无论是控制器还是Create 试图模板都对即将被执行的验证规则和显示的错误信息细节一无所知。验证规则和错误信息仅在Movie类中指定。

如果你稍后想改变验证逻辑,你完全可以将它们定义在一个地方。这样你不用再担心应用程序中不同的部分在执行规则的时候产生不一致2 —— 所有在任何地方使用的验证逻辑都在一个地方定义。这可让代码保持非常的干净,让维护和扩展也变得容易。这就意味你能完全遵照DRY原则3

为Movie模型添加格式

打开Moive.cs文件。System.ComponentModel.DataAnnotations命名空间提供了除内置验证特性集之外的格式特性。你将会为ReleaseDate和Price字段应用DisplayFormat特性和DataType枚举值。下面的代码展示为ReleaseDate和Price属性添加适当的DisplayFormat特性。

        [DataType(DataType.Date)] 
       
public DateTime ReleaseDate { get; set; }
       
       
[DataType(DataType.Currency)]
       
public decimal Price { get; set; }

或者,你可以明确的设置一个DataFormatString值。下面的代码展示发布时间(release data)属性添加一个时间格式字串(即:"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(ErrorMessage = "Title is required")]
   
public string Title { get; set; }

   
[Required(ErrorMessage = "Date is required")]
   
[DisplayFormat(DataFormatString = "{0:d}")]
   
public DateTime ReleaseDate { get; set; }

   
[Required(ErrorMessage = "Genre must be specified")]
   
public string Genre { get; set; }

   
[Required(ErrorMessage = "Price Required")]
   
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
   
[DisplayFormat(DataFormatString = "{0:c}")]
   
public decimal Price { get; set; }

   
[StringLength(5)]
   
public string Rating { get; set; }
}

运行应用程序并路由到Movies控制器。

asp.net mvc3 教程:搜索格式化电影数据

在本系列的下一部分,我们将回顾下当前应用程序并对自动生成的Details和Delete方法做一些改进。

 

MitchellChu翻译备注:

1. 这里所说的注释,就是利用Attribute指定的信息。

2. 这里对being inconsistent with how翻译可能不准确。

3. 突然来这么一句 And it means that that you'll be fully honoring the DRY principle.这个翻译应该是不到位了。

Thursday, May 10, 2012 |

文章评论

No comments posted yet.

发表评论

Please add 8 and 7 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,常年游弋于电子商务,属于互联网行业分类中的杂牌军。当前正在待业中...