共用方式為


將驗證新增至模型 (VB)

Rick Anderson

本教學課程將說明基本概念,簡介如何使用 Microsoft Visual Web Developer 2010 Express Service Pack 1 (Visual Studio Microsoft 的免費版本) 建置 ASP.NET MVC Web 應用程式。 開始之前,請確定您已安裝下列必要項目。 您可按以下連結安裝所有專案:Web Platform Installer。 或者可使用下列連結個別安裝必要條件:

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

本主題隨附內含 VB.NET 原始程式碼的 Visual Web Developer 專案。 下載 VB.NET 版本。 如果您偏好使用 C#,請改參閱本教學課程的 C# 版。

在本節,您會將驗證邏輯新增至 Movie 模型,確保只要使用者嘗試透過應用程式建立或編輯電影,驗證規則就會強制執行。

保持 DRY

ASP.NET MVC 的核心設計原則之一是「DRY」(「不要自我重複」)。 ASP.NET MVC 建議您只要指定一次功能或行為,再反映到應用程式的所有位置。 這可減少需要撰寫的程式碼、避免程式碼出錯,而且也更容易維護。

ASP.NET MVC 和 Entity Framework Core Code First 提供的驗證支援就是執行 DRY 準則的絶佳範例。 您可透過宣告的方式,在單一位置指定驗證規則 (在模型類別中),然後應用程式的所有位置即可強制執行這些規則。

以下說明如何在電影應用程式運用此驗證支援。

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

首先,將驗證邏輯新增至 Movie 類別。

開啟Movie.vb檔案。 在檔案頂端新增 Imports 陳述式,並參照 System.ComponentModel.DataAnnotations 命名空間:

Imports System.ComponentModel.DataAnnotations

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

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

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

驗證屬性會指定您想要強制執行模型屬性套用的行為。 Required 屬性指示,屬性必須有值;在本例中,電影必須有 TitleReleaseDateGenrePrice 屬性,才視為有效。 Range 屬性會將值限制在指定的範圍內。 StringLength 屬性可讓您設定字串屬性的最大長度,並選擇性設定其最小長度。

Code First 會先確保您對模型類別指定的驗證規則將強制執行,應用程式才會將變更儲存至資料庫。 例如,下列程式碼會在呼叫 SaveChanges 方法時擲回例外狀況,因為缺少幾個必要的 Movie 屬性值,且價格是零 (超出有效範圍)。

Dim db As New MovieDBContext()

Dim movie As New Movie()
movie.Title = "Gone with the Wind"
movie.Price = 0.0D

db.Movies.Add(movie)
db.SaveChanges() ' <= Will throw validation exception

由 .NET Framework 自動強制執行驗證規則可強化應用程式。 它也確保您不會忘記要驗證某些項目,不小心讓不正確的資料進入資料庫。

以下是更新 Movie.vb 檔案的完整程式代碼清單:

Imports System.Data.Entity
Imports System.ComponentModel.DataAnnotations

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

Public Class MovieDBContext
    Inherits DbContext
    Public Property Movies() As DbSet(Of Movie)
End Class

ASP.NET MVC 的驗證錯誤 UI

重新執行應用程式,並瀏覽至 /Movies URL。

按一下 [建立電影] 連結以新增新電影。 以一些無效值填入表單,然後按一下 [建立] 按鈕。

8_validationErrors

請注意表單會自動使用背影色醒目提示包含無效資料的文字方塊,並在每個文字方塊旁顯示對應的驗證錯誤訊息。 錯誤訊息符合您在標註 Movie 類別時指定的錯誤字串。 用戶端 (使用 JavaScript) 與伺服器端 (若使用者已停用 JavaScript) 都會強制執行這些錯誤。

真正的好處是,您不需要變更 類別或 MoviesController Create.vbhtml 檢視中的單行程序代碼,才能啟用此驗證 UI。 稍早在本教學課程中,您所建立的控制器和檢視會自動接取您在 Movie 模型類型中使用屬性指定的驗證規則。

Create View 和 Create Action 方法如何執行驗證

您可能奇怪如何在不更新控制器或檢視程式碼的狀況下產生驗證 UI。 下個清單顯示 Create 方法在 MovieController 類別中的外觀。 這些方法與您稍早在本教學課程建立的無異。

'
' GET: /Movies/Create

Function Create() As ViewResult
    Return View()
End Function

'
' POST: /Movies/Create

<HttpPost()>
Function Create(movie As Movie) As ActionResult
    If ModelState.IsValid Then
        db.Movies.Add(movie)
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(movie)
End Function

第一個動作方法會顯示初始建立表單。 第二個方法會處理表單張貼。 第二個 Create 方法會呼叫 ModelState.IsValid 檢查電影是否有任何驗證錯誤。 呼叫此方法會評估已套用至物件的所有驗證屬性。 如果物件有驗證錯誤,則 Create 方法會再次顯示表單。 如果沒有任何錯誤,方法即會將新的電影儲存到資料庫。

以下是您稍早在教學課程中建立的 Create.vbhtml 檢視範本。 上述動作方法會使用它來顯示初始表單,以及在發生錯誤時重新顯示它。

@ModelType MvcMovie.Movie

@Code
    ViewData("Title") = "Create"
End Code

<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(Function(model) model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Title)
            @Html.ValidationMessageFor(Function(model) model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ReleaseDate)
            @Html.ValidationMessageFor(Function(model) model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Genre)
            @Html.ValidationMessageFor(Function(model) model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Price)
            @Html.ValidationMessageFor(Function(model) model.Price)
        </div>

 <div class="editor-label">
     @Html.LabelFor(Function(model) model.Rating)
 </div>
 <div class="editor-field">
     @Html.EditorFor(Function(model) model.Rating)
     @Html.ValidationMessageFor(Function(model) model.Rating)
 </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
End Using

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

請注意程式碼如何使用 Html.EditorFor 協助程序來輸出每個 Movie 屬性的 <input> 元素。 此協助程式旁邊是 Html.ValidationMessageFor 協助程式方法的呼叫。 這兩個協助程式方法會使用控制器傳遞給檢視的模型物件 (在此例中為 Movie 物件)。 這些方法會自動尋找模型指定的驗證屬性,並視情況顯示錯誤訊息。

這個方法最棒的是,控制器和 Create 檢視範本對要強制執行的實際驗證規則,或顯示的特定錯誤訊息,全都一無所知。 只有在 Movie 類別中才能指定驗證規則和錯誤字串。

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

新增格式設定至電影模型

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

<DataType(DataType.Date)>
    Public Property ReleaseDate() As Date

     <DataType(DataType.Currency)>
    Public Property Price() As Decimal

或者可明確設定 DataFormatString 值。 下列程式碼顯示具有日期格式字串 (即「d」) 的版本日期屬性。 您可使用此方式指定不要在版本日期中顯示時間。

<DisplayFormat(DataFormatString:="{0:d}")>
    Public Property ReleaseDate() As Date

下列程式碼會將 Price 屬性格式化為貨幣。

<DisplayFormat(DataFormatString:="{0:c}")>
    Public Property Price() As Decimal

完整的 Movie 類別顯示如下。

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    <DataType(DataType.Date)>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    <DataType(DataType.Currency)>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

執行應用程式並瀏覽至 Movies 控制器。

8_format_SM

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