將驗證新增至模型 (C#)

作者 :Rick Anderson

注意

本教學課程的更新版本可在此處使用 ASP.NET MVC 5 和 Visual Studio 2013。 更安全、更容易遵循並示範更多功能。

本教學課程將教導您使用 Microsoft Visual Web Developer 2010 Express Service Pack 1 建置 ASP.NET MVC Web 應用程式的基本概念,這是免費的 Microsoft Visual Studio 版本。 開始之前,請確定您已安裝下列必要條件。 您可以按一下下列連結來安裝所有元件: Web Platform Installer。 或者,您可以使用下列連結個別安裝必要條件:

如果您使用 Visual Studio 2010 而非 Visual Web Developer 2010,請按一下下列連結來安裝必要條件: Visual Studio 2010 必要條件

具有 C# 原始程式碼的 Visual Web Developer 專案隨附于本主題中。 下載 C# 版本。 如果您偏好 Visual Basic,請切換至本教學課程的 Visual Basic 版本

在本節中,您會將驗證邏輯新增至 Movie 模型,而且您會確保每當使用者嘗試使用應用程式建立或編輯電影時,都會強制執行驗證規則。

讓事物保持幹

ASP.NET MVC 的核心設計原則之一是 DRY (「不要自行重複」) 。 ASP.NET MVC 鼓勵您只指定一次功能或行為,然後將它反映在應用程式中的任何地方。 這可減少您需要撰寫的程式碼數量,並讓您撰寫的程式碼更容易維護。

ASP.NET MVC 和 Entity Framework Code First 所提供的驗證支援是 DRY 原則運作的絕佳範例。 您可以在模型類別中宣告方式指定驗證規則 () ,然後在應用程式中的任何地方強制執行這些規則。

讓我們看看如何在電影應用程式中利用此驗證支援。

將驗證規則新增至電影模型

首先,您會將一些驗證邏輯新增至 Movie 類別。

開啟 Movie.cs 檔案。 using在參考 System.ComponentModel.DataAnnotations 命名空間的檔案頂端新增 語句:

using System.ComponentModel.DataAnnotations;

命名空間是.NET Framework的一部分。 它提供一組內建的驗證屬性,您可以宣告方式套用至任何類別或屬性。

現在更新 Movie 類別,以利用內 Required 建 、 StringLengthRange 驗證屬性。 使用下列程式碼作為套用屬性的位置範例。

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 表示屬性必須有值;在此範例中,電影必須有 、 ReleaseDateGenrePrice 屬性的值 Title ,才能有效。 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。

按一下 [ 建立電影 ] 連結以新增電影。 以一些不正確值填寫表單,然後按一下 [ 建立 ] 按鈕。

8_validationErrors

請注意,表單如何自動使用背景色彩反白顯示包含無效資料的文字方塊,併發出每個文字方塊旁邊的適當驗證錯誤訊息。 錯誤訊息符合您在標注 Movie 類別時所指定的錯誤字串。 如果使用者已停用 JavaScript () ,則會使用 JavaScript) 和伺服器端 (強制執行這些錯誤。

真正的優點是,您不需要變更 類別或Create.cshtml檢視中的 MoviesController 單行程式碼,才能啟用此驗證 UI。 您稍早在本教學課程中建立的控制器和檢視會自動挑選您在模型類別上使用 Movie 屬性指定的驗證規則。

建立檢視和建立動作方法中的驗證發生方式

您可能奇怪如何在不更新控制器或檢視程式碼的狀況下產生驗證 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 表單。 第二個會處理表單貼文。 第二 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 如何使用協助程式來輸出 <input> 每個 Movie 屬性的 元素。 此協助程式旁的呼叫是協助程式方法的 Html.ValidationMessageFor 呼叫。 這兩個協助程式方法會使用控制器傳遞至檢視 (的模型物件,在此案例中為 Movie 物件) 。 它們會自動尋找模型上指定的驗證屬性,並視需要顯示錯誤訊息。

這種方法真的不錯,就是控制器和建立檢視範本都不知道強制執行的實際驗證規則或顯示的特定錯誤訊息。 只有在 Movie 類別中才能指定驗證規則和錯誤字串。

如果您想要稍後變更驗證邏輯,可以在一個位置執行此動作。 您不必擔心應用程式的不同部分會與規則強制執行的方式不一致,所有的驗證邏輯都是在同一個地方定義,用於所有位置。 這會讓程式碼非常整齊乾淨,容易維護及發展。 這表示您會完全接受 DRY 原則。

將格式新增至電影模型

開啟 Movie.cs 檔案。 除了一組內建的驗證屬性之外,System.ComponentModel.DataAnnotations 命名空間還提供了格式屬性。 您會將 DisplayFormat 屬性和 DataType 列舉值套用至發行日期和價格欄位。 下列程式碼會示範具有適當 DisplayFormat 屬性 (attribute) 的 ReleaseDatePrice 屬性 (property)。

[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 控制器。

8_format_SM

在數列的下一個部分中,我們會檢閱應用程式,並對自動產生的 DetailsDelete 方法進行一些改良。