ASP.NET MVC 5 - 給數據模型添加校驗器

在本節中將會給Movie模型添加驗證邏輯。而且確保這些驗證規則在用戶建立或編輯電影時被執行。html

拒絕重複DRY

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類,以利用內置的RequiredStringLength, RegularExpressionRange驗證屬性。如下面的代碼爲例,以應用驗證屬性。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):瀏覽器

clip_image002

在上面的圖片中,你能夠看到全部的字符串字段被設置爲了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:

clip_image004

該字符串字段顯示新的長度限制和流派字段(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會自動強制執行的驗證規則, 有助於使你的應用程序更加健壯。它還確保能夠不會忘記驗證的東西,即在不經意間不會讓壞的數據寫入數據庫。

ASP.NET MVC 的驗證錯誤UI

從新運行應用程序,瀏覽 /Movies的 URL。

單擊Create New連接,來添加一部新電影。在窗體中填寫一些無效值,而後單擊Create按鈕。

如同jQuery的客戶端驗證來檢測到錯誤時,它會顯示一個錯誤消息。

ff9

注意,爲了使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。

clip_image008

clip_image010

下圖顯示瞭如何在火狐瀏覽器中禁用 JavaScript。

clip_image012

下圖顯示瞭如何在 Chrome 瀏覽器中禁用 JavaScript。

clip_image014

下面是框架代碼在以前的教程中生成的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原則。

使用DataType屬性

打開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; }
}

在教程的下一部分,咱們先會看看代碼,而後再改進一下自動生成的DetailsDelete 方法。有了本節介紹的內容,相信你們已經掌握了給數據模型添加校驗器的方法。後面你們在進行MVC開發時,一方面能夠運用本節知識,一方面也能夠藉助一些開發工具。ComponentOne Studio ASP.NET MVC 是一款針對 MVC 平臺的控件包,能提供從桌面到移動設備的用戶體驗。

相關文章
相關標籤/搜索