ASP.NET Core3.1 MVC 添加驗證規則

本節內容:html

  • 向 Movie 模型添加了驗證邏輯。
  • 確保每當用戶建立或編輯電影時,都會強制執行驗證規則。

堅持 DRY 原則

MVC 的設計原則之一是 DRY(「不要自我重複」)。 ASP.NET Core MVC 支持你僅指定一次功能或行爲,而後使它應用到整個應用中。 這能夠減小所需編寫的代碼量,並使編寫的代碼更少出錯,更易於測試和維護。jquery

MVC 和 Entity Framework Core Code First 提供的驗證支持是 DRY 原則在實際操做中的極佳示例。 能夠在一個位置(模型類中)以聲明方式指定驗證規則,而且在應用中的全部位置強制執行。git

將驗證規則添加到電影模型

DataAnnotations 命名空間提供一組內置驗證特性,可經過聲明方式應用於類或屬性。 DataAnnotations 還包含 DataType 等格式特性,有助於格式設置但不提供任何驗證。github

更新 Movie 類以使用內置的 RequiredStringLengthRegularExpression 和 Range 驗證特性。數據庫

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

 

驗證特性指定要對應用這些特性的模型屬性強制執行的行爲:瀏覽器

  • Required 和 MinimumLength 特性表示屬性必須有值;但用戶可輸入空格來知足此驗證。服務器

  • RegularExpression 特性用於限制可輸入的字符。 在上述代碼中,即「Genre」(分類):mvc

    • 只能使用字母。
    • 第一個字母必須爲大寫。 不容許使用空格、數字和特殊字符。
  • RegularExpression「Rating」(分級):async

    • 要求第一個字符爲大寫字母。
    • 容許在後續空格中使用特殊字符和數字。 「PG-13」對「分級」有效,但對於「分類」無效。
  • Range 特性將值限制在指定範圍內。ide

  • StringLength 特性使你可以設置字符串屬性的最大長度,以及可選的最小長度。

  • 從本質上來講,須要值類型(如 decimalintfloatDateTime),但不須要 [Required] 特性。

讓 ASP.NET Core 強制自動執行驗證規則有助於提高你的應用的可靠性。 同時它能確保你沒法忘記驗證某些內容,並防止你無心中將錯誤數據導入數據庫。

驗證錯誤 UI

運行應用並導航到電影控制器。

點擊「新建」鏈接添加新電影 的連接。 使用無效值填寫表單。 當 jQuery 客戶端驗證檢測到錯誤時,會顯示一條錯誤消息。

帶有多個 jQuery 客戶端驗證錯誤的電影視圖表單

備註

可能沒法在小數字段中輸入十進制逗號。 若要使 jQuery 驗證支持使用逗號(「,」)表示小數點的的非英語區域設置,以及支持非美國英語日期格式,必須執行使應用全球化的步驟。 有關添加十進制逗號的說明,請參閱 GitHub 問題 4076

請注意表單如何自動呈現每一個包含無效值的字段中相應的驗證錯誤消息。 客戶端(使用 JavaScript 和 jQuery)和服務器端(若用戶禁用 JavaScript)都一定會遇到這些錯誤。

明顯的好處在於不須要在 MoviesController 類或 Create.cshtml 視圖中更改單個代碼行來啓用此驗證 UI 。 在本教程前面建立的控制器和視圖會自動選取驗證規則,這些規則是經過在 Movie 模型類的屬性上使用驗證特性所指定的。 使用 Edit 操做方法測試驗證後,即已應用相同的驗證。

存在客戶端驗證錯誤時,不會將表單數據發送到服務器。 可經過使用 Fiddler 工具或 F12 開發人員工具在 HTTP Post 方法中設置斷點來對此進行驗證。

驗證工做原理

你可能想知道在不對控制器或視圖中的代碼進行任何更新的狀況下,驗證 UI 是如何生成的。 下列代碼顯示兩種 Create 方法。

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}
 
// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

 

第一個 (HTTP GET) Create 操做方法顯示初始的「建立」表單。 第二個 ([HttpPost]) 版本處理表單發佈。 第二個 Create 方法([HttpPost] 版本)調用 ModelState.IsValid 以檢查電影是否有任何驗證錯誤。 調用此方法將評估已應用於對象的任何驗證特性。 若是對象有驗證錯誤,則 Create 方法會從新顯示此表單。 若是沒有錯誤,此方法則將新電影保存在數據庫中。 在咱們的電影示例中,在檢測到客戶端上存在驗證錯誤時,表單不會發布到服務器。當存在客戶端驗證錯誤時,第二個 Create 方法永遠不會被調用。 若是在瀏覽器中禁用 JavaScript,客戶端驗證將被禁用,而你能夠測試 HTTP POST Create 方法 ModelState.IsValid 檢測任何驗證錯誤。

能夠在 [HttpPost] Create 方法中設置斷點,並驗證方法從未被調用,客戶端驗證在檢測到存在驗證錯誤時不會提交表單數據。 若是在瀏覽器中禁用 JavaScript,而後提交錯誤的表單,將觸發斷點。 在沒有 JavaScript 的狀況下仍然能夠進行完整的驗證。

如下圖片顯示如何在 FireFox 瀏覽器中禁用 JavaScript。

Firefox:在「選項」的「內容」選項卡上,取消選中「啓用 Javascript」複選框。

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

Google Chrome:在「內容」設置的 Javascript 部分中,選擇「不容許任何網站運行 JavaScript」。

禁用 JavaScript 後,發佈無效數據並單步執行調試程序。

在對無效數據進行調試時,ModelState.IsValid 上的 Intellisense 顯示值爲 false。

Create.cshtml 視圖模板的一部分在如下標記中顯示 :

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>          
        
        @*Markup removed for brevity.*@

 

操做方法使用上述標記來顯示初始表單,並在發生錯誤時從新顯示此表單。

輸入標記幫助程序使用 DataAnnotations 特性,並在客戶端上生成 jQuery 驗證所需的 HTML 特性。 驗證標記幫助程序用於顯示驗證錯誤。 有關詳細信息,請參閱驗證

此方法真正好的一點是:不管是控制器仍是 Create 視圖模板都不知道強制實施的實際驗證規則或顯示的特定錯誤消息。 僅可在 Movie 類中指定驗證規則和錯誤字符串。 這些相同的驗證規則自動應用於 Edit 視圖和可能建立用於編輯模型的任何其餘視圖模板。

須要更改驗證邏輯時,能夠經過將驗證特性添加到模型在同一個位置實現此操做。(在此示例中爲 Movie 類)。 無需擔憂對應用程序的不一樣部分所強制執行規則的方式不一致 - 全部驗證邏輯都將定義在一個位置並用於整個應用程序。 這使代碼很是簡潔,而且更易於維護和改進。 這意味着對 DRY 原則的徹底遵照。

使用 DataType 特性

打開 Movie.cs 文件並檢查 Movie 類 。 除了一組內置的驗證特性,System.ComponentModel.DataAnnotations 命名空間還提供格式特性。 咱們已經在發佈日期和價格字段中應用了 DataType 枚舉值。 如下代碼顯示具備適當 DataType 特性的 ReleaseDate 和 Price 屬性。

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
 
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

 

DataType 屬性僅提供相關提示來幫助視圖引擎設置數據格式(並提供元素/屬性,例如向 URL 提供 <a> 和向電子郵件提供 <a href="mailto:EmailAddress.com">)。 可使用 RegularExpression 特性驗證數據的格式。 DataType 屬性用於指定比數據庫內部類型更具體的數據類型,它們不是驗證屬性。 在此示例中,咱們只想跟蹤日期,而不是時間。 DataType 枚舉提供了多種數據類型,例如日期、時間、電話號碼、貨幣、電子郵件地址等。 應用程序還可經過 DataType 特性自動提供類型特定的功能。 例如,能夠爲 DataType.EmailAddress 建立 mailto: 連接,而且能夠在支持 HTML5 的瀏覽器中爲 DataType.Date 提供日期選擇器。 DataType 特性發出 HTML 5 data-(讀做 data dash)特性供 HTML 5 瀏覽器理解。 DataType 特性不提供任何驗證 。

DataType.Date 不指定顯示日期的格式。 默認狀況下,數據字段根據基於服務器的 CultureInfo 的默認格式進行顯示。

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

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

 

ApplyFormatInEditMode 設置指定在文本框中顯示值以進行編輯時也應用格式。 (你可能不想爲某些字段執行此操做 — 例如對於貨幣值,你可能不但願文本框中的貨幣符號可編輯。)

能夠單獨使用 DisplayFormat 特性,但一般建議使用 DataType 特性。 DataType 特性傳達數據的語義而不是傳達如何在屏幕上呈現數據,並提供 DisplayFormat 不具有的如下優點:

  • 瀏覽器可啓用 HTML5 功能(例如顯示日曆控件、區域設置適用的貨幣符號、電子郵件連接等)

  • 默認狀況下,瀏覽器將根據區域設置採用正確的格式呈現數據。

  • DataType 特性使 MVC 可以選擇正確的字段模板來呈現數據(若是 DisplayFormat 由自身使用,則使用的是字符串模板)。

備註

jQuery 驗證不適用於 Range 屬性和 DateTime。 例如,如下代碼將始終顯示客戶端驗證錯誤,即使日期在指定的範圍內:

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

須要禁用 jQuery 日期驗證才能使用具備 DateTime 的 Range 特性。 一般,在模型中編譯固定日期是不恰當的,所以不推薦使用 Range 特性和 DateTime

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

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

 

在本系列的下一部分中,咱們將回顧應用,並對自動生成的 Details 和 Delete 方法進行一些改進。

其餘資源

相關文章
相關標籤/搜索