將驗證新增至模型 (C#)
注意
這裡提供本教學課程的更新版本,其中使用 ASP.NET MVC 5 和 Visual Studio 2013。 新的教學指示更安全、更易於遵循且示範更多功能。
本教學課程將說明基本概念,簡介如何使用 Microsoft Visual Web Developer 2010 Express Service Pack 1 (Visual Studio Microsoft 的免費版本) 建置 ASP.NET MVC Web 應用程式。 開始之前,請確定您已安裝下列必要項目。 您可按以下連結安裝所有專案:Web Platform Installer。 或者可使用下列連結個別安裝必要條件:
- Visual Studio Web Developer Express SP1 必要條件
- ASP.NET MVC 3 工具更新
- SQL Server Compact 4.0 (執行階段 + 工作支援)
如果您使用 Visual Studio 2010 而非 Visual Web Developer 2010,請按以下連結安裝必要條件:Visual Studio 2010 必要條件。
本主題隨附內含 C# 原始程式碼的 Visual Web Developer 專案。 下載 C# 版本。 如果您偏好使用 Visual Basic,請切換至本教學課程的 Visual Basic version 版。
在本節中,您會將驗證邏輯新增至 Movie
模型,確保只要使用者嘗試以應用程式建立或編輯電影,驗證規則就會強制執行。
保持 DRY
ASP.NET MVC 的核心設計原則之一是「DRY」(「不要自我重複」)。 ASP.NET MVC 建議您只要指定一次功能或行為,再反映到應用程式的所有位置。 這可減少需要撰寫的程式碼、避免程式碼出錯,而且也更容易維護。
ASP.NET MVC 和 Entity Framework Core Code First 提供的驗證支援就是執行 DRY 準則的絶佳範例。 您可透過宣告的方式,在單一位置指定驗證規則 (在模型類別中),然後應用程式的所有位置即可強制執行這些規則。
以下說明如何在電影應用程式運用此驗證支援。
將驗證規則新增至電影模型
首先,將驗證邏輯新增至 Movie
類別。
開啟 Movie.cs 檔案。 在檔案頂端新增 using
陳述式,並參照 System.ComponentModel.DataAnnotations
命名空間:
using System.ComponentModel.DataAnnotations;
命名空間是 .NET Framework 的一部分。 提供一組內建的驗證屬性,您可透過宣告方式將其套用至類別或屬性。
現在,請更新 Movie
類別,以利用內建的 Required
、StringLength
和 Range
驗證屬性。 以下列程式碼作為套用屬性的位置範例。
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; }
[Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
public decimal Price { get; set; }
[StringLength(5)]
public string Rating { get; set; }
}
驗證屬性會指定您想要強制執行模型屬性套用的行為。 Required
屬性指示,屬性必須有值;在本例中,電影必須有 Title
、ReleaseDate
、Genre
和 Price
屬性,才視為有效。 Range
屬性會將值限制在指定的範圍內。 StringLength
屬性可讓您設定字串屬性的最大長度,並選擇性設定其最小長度。
Code First 會先確保您對模型類別指定的驗證規則將強制執行,應用程式才會將變更儲存至資料庫。 例如,下列程式碼會在呼叫 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 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; }
public DateTime ReleaseDate { get; set; }
[Required(ErrorMessage = "Genre must be specified")]
public string Genre { get; set; }
[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
重新執行應用程式,並瀏覽至 /Movies URL。
按一下 [建立電影] 連結以新增新電影。 以一些無效值填入表單,然後按一下 [建立] 按鈕。
請注意表單會自動使用背影色醒目提示包含無效資料的文字方塊,並在每個文字方塊旁顯示對應的驗證錯誤訊息。 錯誤訊息符合您在標註 Movie
類別時指定的錯誤字串。 用戶端 (使用 JavaScript) 與伺服器端 (若使用者已停用 JavaScript) 都會強制執行這些錯誤。
最實際的好處是,您不需要為了啟用這項驗證 UI 而變更 MoviesController
類別或 Create.cshtml 檢視的任一行程式碼。 稍早在本教學課程中,您所建立的控制器和檢視會自動接取您在 Movie
模型類型中使用屬性指定的驗證規則。
Create View 和 Create Action 方法如何執行驗證
您可能奇怪如何在不更新控制器或檢視程式碼的狀況下產生驗證 UI。 下個清單顯示 Create
方法在 MovieController
類別中的外觀。 這些方法與您稍早在本教學課程建立的無異。
//
// 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);
}
第一個動作方法會顯示初始建立表單。 第二個方法會處理表單張貼。 第二個 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
類別中才能指定驗證規則和錯誤字串。
如果您想要稍後再變更驗證邏輯,可在同一個位置執行。 您不必擔心應用程式的不同部分會與規則強制執行的方式不一致,所有的驗證邏輯都是在同一個地方定義,用於所有位置。 這會讓程式碼非常整齊乾淨,容易維護及發展。 也就是說,您完全彰顯了 DRY 原則。
新增格式設定至電影模型
開啟 Movie.cs 檔案。 除了一組內建的驗證屬性之外,System.ComponentModel.DataAnnotations
命名空間還提供了格式屬性。 您要將 DisplayFormat
屬性和 DataType
列舉值套用至發行日期和價格欄位。 下列程式碼會示範 ReleaseDate
和 Price
屬性 (具有適當的 DisplayFormat
屬性)。
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
或者可明確設定 DataFormatString
值。 下列程式碼顯示具有日期格式字串 (即「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; }
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }
[Required(ErrorMessage = "Genre must be specified")]
public string Genre { get; set; }
[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
控制器。
在數列的下一個部分中,我們會檢閱應用程式,並對自動產生的 Details
和 Delete
方法進行一些改良。