將驗(yàn)證添加到 ASP.NET Core Razor 頁面

2019-04-17 08:57 更新

本部分中向 Movie 模型添加了驗(yàn)證邏輯。 每當(dāng)用戶創(chuàng)建或編輯電影時(shí),都會(huì)強(qiáng)制執(zhí)行驗(yàn)證規(guī)則。

驗(yàn)證

軟件開發(fā)的一個(gè)關(guān)鍵原則被稱為 DRY(即“不要自我重復(fù)”)。 Razor 頁面鼓勵(lì)進(jìn)行僅指定一次功能的開發(fā),且功能在整個(gè)應(yīng)用中反映。 DRY 可以幫助:

  • 減少應(yīng)用中的代碼量。
  • 使代碼更加不易出錯(cuò),且更易于測試和維護(hù)。

Razor 頁面和 Entity Framework 提供的驗(yàn)證支持是 DRY 原則的極佳示例。 驗(yàn)證規(guī)則在模型類中的某處以聲明方式指定,且在應(yīng)用的所有位置強(qiáng)制執(zhí)行。

將驗(yàn)證規(guī)則添加到電影模型

打開 Models/Movie.cs 文件。 DataAnnotations 提供一組內(nèi)置驗(yàn)證特性,可通過聲明方式應(yīng)用于類或?qū)傩浴?nbsp;DataAnnotations 還包含 DataType 等格式特性,有助于格式設(shè)置但不提供驗(yàn)證。

更新 Movie 類以使用 Required、StringLength、RegularExpression 和 Range 驗(yàn)證特性。

C#

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

驗(yàn)證特性用于指定模型屬性上強(qiáng)制執(zhí)行的行為:

  • Required 和 MinimumLength 特性指示屬性必須具有一個(gè)值。 但是,用戶可以隨時(shí)輸入空格以對可以為 null 的類型進(jìn)行驗(yàn)證約束。 從本質(zhì)上來說,需要不可以為 null 的值類型(如 decimal、int、float 和 DateTime),但不需要 Required 特性。
  • RegularExpression 特性限制用戶可以輸入的字符。 在前面的代碼中,Genre 必須以一個(gè)或多個(gè)大寫字母開始,并且后接零個(gè)或多個(gè)字母、單引號(hào)或雙引號(hào)、空白字符或短劃線。 Rating 必須以一個(gè)或多個(gè)大寫字母開始,并且后接零個(gè)或多個(gè)字母、數(shù)字、單引號(hào)或雙引號(hào)、空白字符或短劃線。
  • Range 特性將值限制在指定范圍內(nèi)。
  • StringLength 特性設(shè)置字符串的最大長度,且可視情況設(shè)置最小長度。

讓 ASP.NET Core 強(qiáng)制自動(dòng)執(zhí)行驗(yàn)證規(guī)則有助于提升應(yīng)用的可靠性。 自動(dòng)驗(yàn)證模型有助于保護(hù)應(yīng)用,因?yàn)樘砑有麓a時(shí)無需手動(dòng)應(yīng)用它們。

Razor 頁面中的“驗(yàn)證錯(cuò)誤”UI

運(yùn)行應(yīng)用并導(dǎo)航到“頁面/電影”。

選擇“新建”鏈接。 使用無效值填寫表單。 當(dāng) jQuery 客戶端驗(yàn)證檢測到錯(cuò)誤時(shí),會(huì)顯示一條錯(cuò)誤消息。

帶有多個(gè) jQuery 客戶端驗(yàn)證錯(cuò)誤的電影視圖表單

 備注

可能無法在小數(shù)字段中輸入十進(jìn)制逗號(hào)。 若要使 jQuery 驗(yàn)證支持使用逗號(hào)(“,”)表示小數(shù)點(diǎn)的的非英語區(qū)域設(shè)置,以及支持非美國英語日期格式,必須執(zhí)行使應(yīng)用全球化的步驟。 有關(guān)添加十進(jìn)制逗號(hào)的說明,請參閱 GitHub 問題 4076。

請注意表單如何自動(dòng)呈現(xiàn)每個(gè)包含無效值的字段中的驗(yàn)證錯(cuò)誤消息。 客戶端(使用 JavaScript 和 jQuery)和服務(wù)器端(若用戶禁用 JavaScript)都必定會(huì)遇到這些錯(cuò)誤。

一項(xiàng)重要優(yōu)勢是,無需在“創(chuàng)建”或“編輯”頁面中更改代碼。 在模型應(yīng)用 DataAnnotations 后,即已啟用驗(yàn)證 UI。 本教程中自動(dòng)創(chuàng)建的 Razor 頁面自動(dòng)選取了驗(yàn)證規(guī)則(使用 Movie 模型類的屬性上的驗(yàn)證特性)。 使用“編輯”頁面測試驗(yàn)證后,即已應(yīng)用相同驗(yàn)證。

存在客戶端驗(yàn)證錯(cuò)誤時(shí),不會(huì)將表單數(shù)據(jù)發(fā)布到服務(wù)器。 請通過以下一種或多種方法驗(yàn)證是否未發(fā)布表單數(shù)據(jù):

  • 在 OnPostAsync 方法中放置一個(gè)斷點(diǎn)。 提交表單(選擇“創(chuàng)建”或“保存”)。 從未命中斷點(diǎn)。
  • 使用 Fiddler 工具。
  • 使用瀏覽器開發(fā)人員工具監(jiān)視網(wǎng)絡(luò)流量。

服務(wù)器端驗(yàn)證

在瀏覽器中禁用 JavaScript 后,提交出錯(cuò)表單將發(fā)布到服務(wù)器。

(可選)測試服務(wù)器端驗(yàn)證:

  • 在瀏覽器中禁用 JavaScript。 可以使用瀏覽器的開發(fā)人員工具執(zhí)行此操作。 如果無法在瀏覽器中禁用 JavaScript,請嘗試其他瀏覽器。
  • 在“創(chuàng)建”或“編輯”頁面的 OnPostAsync 方法中設(shè)置斷點(diǎn)。
  • 提交帶有驗(yàn)證錯(cuò)誤的表單。
  • 驗(yàn)證模型狀態(tài)是否無效:C#復(fù)制if (!ModelState.IsValid) { return Page(); }

以下代碼顯示了之前在本教程中設(shè)定其基架的“Create.cshtml”的一部分。 它用于在“創(chuàng)建”和“編輯”頁面中顯示初始表單并在發(fā)生錯(cuò)誤后重新顯示表單。

CSHTML

<form method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Movie.Title" class="control-label"></label>
        <input asp-for="Movie.Title" class="form-control" />
        <span asp-validation-for="Movie.Title" class="text-danger"></span>
    </div>

輸入標(biāo)記幫助程序使用 DataAnnotations 特性并在客戶端生成 jQuery 驗(yàn)證所需的 HTML 特性。 驗(yàn)證標(biāo)記幫助程序用于顯示驗(yàn)證錯(cuò)誤。 有關(guān)詳細(xì)信息,請參閱驗(yàn)證。

“創(chuàng)建”和“編輯”頁面中沒有驗(yàn)證規(guī)則。 僅可在 Movie 類中指定驗(yàn)證規(guī)則和錯(cuò)誤字符串。 這些驗(yàn)證規(guī)則將自動(dòng)應(yīng)用于編輯 Movie 模型的 Razor 頁面。

需要更改驗(yàn)證邏輯時(shí),也只能在該模型中更改。 將始終在整個(gè)應(yīng)用程序中應(yīng)用驗(yàn)證(在一處定義驗(yàn)證邏輯)。 單處驗(yàn)證有助于保持代碼干凈,且更易于維護(hù)和更新。

使用 DataType 特性

檢查 Movie 類。 除了一組內(nèi)置的驗(yàn)證特性,System.ComponentModel.DataAnnotations 命名空間還提供格式特性。 DataType 特性應(yīng)用于 ReleaseDate 和 Price 屬性。

C#

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

DataType 特性僅提供相關(guān)提示來幫助視圖引擎設(shè)置數(shù)據(jù)格式(并提供特性,例如向 URL 提供 <a>和向電子郵件提供 <a href="mailto:EmailAddress.com">)。 使用 RegularExpression 特性驗(yàn)證數(shù)據(jù)的格式。 DataType 屬性用于指定比數(shù)據(jù)庫內(nèi)部類型更具體的數(shù)據(jù)類型。 DataType 特性不是驗(yàn)證特性。 示例應(yīng)用程序中僅顯示日期,不顯示時(shí)間。

DataType 枚舉提供了多種數(shù)據(jù)類型,例如日期、時(shí)間、電話號(hào)碼、貨幣、電子郵件地址等。 應(yīng)用程序還可通過 DataType 特性自動(dòng)提供類型特定的功能。 例如,可為 DataType.EmailAddress 創(chuàng)建 mailto: 鏈接。 可在支持 HTML5 的瀏覽器中為 DataType.Date 提供日期選擇器。 DataType 特性發(fā)出 HTML 5 data-(讀作 data dash)特性供 HTML 5 瀏覽器使用。 DataType 特性不提供任何驗(yàn)證。

DataType.Date 不指定顯示日期的格式。 默認(rèn)情況下,數(shù)據(jù)字段根據(jù)基于服務(wù)器的 CultureInfo 的默認(rèn)格式進(jìn)行顯示。

要使 Entity Framework Core 能將 Price 正確地映射到數(shù)據(jù)庫中的貨幣,則必須使用 [Column(TypeName = "decimal(18, 2)")] 數(shù)據(jù)注釋。 有關(guān)詳細(xì)信息,請參閱數(shù)據(jù)類型。

DisplayFormat 特性用于顯式指定日期格式:

C#

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

ApplyFormatInEditMode 設(shè)置用于指定在顯示值進(jìn)行編輯時(shí)需應(yīng)用格式。 可能不希望某些字段具有此行為。 例如,在貨幣值中,可能不希望編輯 UI 中存在貨幣符號(hào)。

可單獨(dú)使用 DisplayFormat 特性,但通常建議使用 DataType 特性。 DataType 特性傳達(dá)數(shù)據(jù)的語義而不是傳達(dá)如何在屏幕上呈現(xiàn)數(shù)據(jù),并提供 DisplayFormat 不具備的以下優(yōu)勢:

  • 瀏覽器可啟用 HTML5 功能(例如顯示日歷控件、區(qū)域設(shè)置適用的貨幣符號(hào)、電子郵件鏈接等)
  • 默認(rèn)情況下,瀏覽器將根據(jù)區(qū)域設(shè)置采用正確的格式呈現(xiàn)數(shù)據(jù)。
  • 借助 DataType 特性,ASP.NET Core 框架可選擇適當(dāng)?shù)淖侄文0鍋沓尸F(xiàn)數(shù)據(jù)。 單獨(dú)使用時(shí),DisplayFormat 特性將使用字符串模板。

注意:jQuery 驗(yàn)證不適用于 Range 屬性和 DateTime。 例如,以下代碼將始終顯示客戶端驗(yàn)證錯(cuò)誤,即便日期在指定的范圍內(nèi):

C#

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

通常,在模型中編譯固定日期是不恰當(dāng)?shù)模虼瞬煌扑]使用 Range 特性和 DateTime。

以下代碼顯示組合在一行上的特性:

C#

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

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date"), DataType(DataType.Date)]
    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)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Razor Pages 和 EF Core 入門顯示了 Razor Pages 的高級(jí) EF Core 操作。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)