ASP.NET Core 中文文檔 第二章 指南(4.9)添加驗證


原文:Adding Validation
作者:Rick Anderson
翻譯:謝煬(Kiler)
校對:孟帥洋(書緣)婁宇(Lyrics)許登洋(Seay)

在本章節中你將為 Movie 模型類添加驗證邏輯,以確保用戶在試圖創建或編輯影片數據時強制執行驗證規則。

保持DRY原則

ASP.NET MVC 的核心原則之一是 DRY (“不要重復自己”)。ASP.NET MVC 鼓勵你只指定一次行為或者功能,然后可以在應用程序里面到處使用,這樣大大的減少了需要編寫的代碼量,並且使你編寫不容易出錯,更容易測試,以及更容易維護的代碼。

ASP.NET MVC 和 Entity Framework Core Code First 中的驗證功能,是 DRY 原則實際應用的一個很好的實例。你可以在某個位置(模型類)聲明指定方式的驗證規則,驗證規則可以在整個應用程序中生效。

讓我們來看看如何在電影應用程序中利用驗證功能。

向 Movie 模型中添加驗證規則

打開 Movie.cs 文件。DataAnnotations 提供了一組內置的驗證特性,你可以對任何類或屬性應用。(它也同時包含了一些格式化特性,比如 DataType 用來幫你格式化數據而非提供驗證功能。)

現在修改 Movie 類,利用內置的 RequiredStringLengthRegularExpression 以及 Range 驗證特性。

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)] //手工高亮
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")] //手工高亮
    [StringLength(5)] //手工高亮
    public string Rating { get; set; }
}

驗證特性指定了你想要應用到模型屬性上的驗證行為。Required 以及 MinimumLength 特性表示屬性不能為空,但無法阻止用戶用填寫空格的方式來滿足此驗證條件。RegularExpression 特性用來限制用戶輸入的文字類型。 在上面的例子中,Genre 以及 Rating 只能輸入字母(不允許輸入空格、數字以及特殊字符)。Range 特性限制值在指定的范圍內。StringLength 特性可讓你設定字符串最大長度,以及最小長度(可選)。值類型(如decimal, int, float, DateTime) 本身是必須的,並不需要 [Required] 特性。

ASP.NET 自動執行的驗證規則將有助於使你的應用程序更加健壯。它還確保提醒你不要忘記驗證數據,讓非法數據進入到數據庫中。

MVC 中的驗證錯誤 UI

運行程序並導航到 Movies controller。

點擊 Create New 鏈接創建一個新的 Movie。在表單中填寫一些無效的數據,jQuery 客戶端驗證馬上就會發現錯誤,立刻呈現到界面上。

validation/_static/val.png

注意
你也許無法在 Price 字段中輸入小數點或者逗號。為了讓 jQuery validation 支持非英語環境使用逗號(",")代替小數點,以及非美式英語日期格式,你必須采取措施國際化你的應用程序。參考 附錄資源 獲取更多信息。 現在僅僅輸入整數,比如 10。

請注意,表單在包含無效值的每個字段下自動呈現一個適當的驗證錯誤消息。錯誤包括客戶端(使用 JavaScript 和 jQuery )和服務器端(以防用戶已禁用 JavaScript)。

一個顯而易見的好處是,你並不需要改變 MoviesController 類或者 Create.cshtml 視圖中的一行代碼,就可以實現驗證界面。你在本教程前面創建的控制器和視圖,自動使用你指定的 Movie 模型類的屬性上的驗證特性的驗證規則。使用 Edit 操作方法測試驗證,(與Create 方法)同樣的驗證生效。

表單數據不會被發送到服務器直到沒有客戶端驗證錯誤。你可以在 HTTP Post 方法中設置斷點,並通過使用 Fiddler 工具或者 F12 開發者工具 訪問這個方法來驗證這一點。

創建視圖和創建方法中如何觸發驗證

也許你會好奇生成的控制器或視圖中的代碼沒有任何更新的情況下驗證界面是如何產生的。下一個清單顯示的是兩個 Create 方法。

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Genre,Price,ReleaseDate,Title,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

第一個(HTTP GET) Create 的操作方法顯示初始創建表單。第二個([HttpPost])版本的操作方法負責處理 post 請求。第二個 Create 的方法(HttpPost 版本)調用 ModelState.IsValid 檢查是否有任何驗證錯誤。調用該方法將檢查任何已應用到對象屬性上的驗證。如果對象的 Create 方法驗證錯誤,重新顯示表單。如果沒有錯誤,該方法在數據庫中保存新的 movie。在我們的 movie 例子中,在客戶端驗證檢測到錯誤時,表單將不會發送到服務器,第二個 Create 方法不會被調用。如果你的瀏覽器禁用了 JavaScript,客戶端驗證被禁用,HTTP POST 版本的 Create 方法調用 ModelState.IsValid,以檢查是否存在任何驗證錯誤。

你可以在 [HttpPost] Create 方法中設置一個斷點,用來驗證該方法不會被調用,客戶端驗證發現錯誤時將不提交表單數據。如果你的瀏覽器禁用了 JavaScript ,然后提交有錯誤的表單,斷點會被命中。不支持 JavaScript 的情況下,你仍然可以得到充分驗證。下面的圖片展示了如何在 IE 瀏覽器中禁用 JavaScript 腳本。

validation/_static/p8_IE9_disableJavaScript.png

下面的圖片展示了如何在 FireFox 瀏覽器中禁用 JavaScript 腳本。

validation/_static/ff.png

下面的圖片展示了如何在 Chrome 瀏覽器中禁用 JavaScript 腳本。

validation/_static/chrome.png

在禁用 JavaScript 腳本之后,post 非法數據並在調試器中單步調試。

validation/_static/ms.png

下面是你在本教程前面用基架生成的 Create.cshtml 視圖模板的一部分。它使用上面展示的兩種 action 方法來顯示初始表單並且在發生錯誤時重新顯示。

<form asp-action="Create">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Genre" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Genre" class="form-control" /> <!--手工高亮-->
                <span asp-validation-for="Genre" class="text-danger" /> <!--手工高亮-->
            </div>
        </div>
        @*Markup removed for brevity.*@ <!--手工高亮-->
        <div class="form-group">
            <label asp-for="Rating" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Rating" class="form-control" /> <!--手工高亮-->
                <span asp-validation-for="Rating" class="text-danger" /> <!--手工高亮-->
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

Input Tag Helper 消費 DataAnnotations 特性和產生jQuery驗證所需要在客戶端生成的 HTML 屬性。Validation Tag Helper 負責顯示錯誤信息。更多請參考 Validation

非常棒的是控制器和 Create 視圖模板不知道實際執行的驗證規則或顯示的具體錯誤消息。只需要在 Movie 類里指定驗證規則和錯誤字符串,同樣的驗證規則會自動應用到 Edit 視圖和任何其他視圖模板,你可以創建、編輯你的模型。

如果你想更改驗證邏輯,你可以限定在一處地方(在本例中,是指 Movie 類),為模型添加驗證特性。你不需要擔心應用程序的不同部分執行的規則不一致 —— 所有的驗證邏輯在同一個地方定義然后在各處使用 。這樣可以使得代碼很干凈,而且易於維護和改進。這意味着,你充分遵循了 DRY 原則。

使用 DataType 特性

打開 Movie.cs 文件,並查看 Movie 類。System.ComponentModel.DataAnnotations 命名空間提供了除了內置的驗證特性以外的一套格式化特性。我們已經應用了 DataType 枚舉值到發布日期和價格字段。下面的代碼顯示了 ReleaseDatePrice 字段如何使用 DataType 特性。

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

[Range(1, 100)]
[DataType(DataType.Currency)] //手工高亮
public decimal Price { get; set; }

DataType 特性只用於視圖引擎對數據進行格式化(或者提供給諸如 <A> 標簽 的Url或者 <a href="mailto:EmailAddress.com"> 提供的電子郵件),你可以使用 RegularExpression 特性來驗證數據的格式,DataType 特性用於指定比數據庫的自帶類型更為具體的數據類型,它們不是驗證特性,在本示例中我們只想跟蹤日期,而不需要具體時間。在 DataType 枚舉提供了許多數據類型,如日期、時間、手機號碼、貨幣、電子郵件地址等。DataType 特性一樣可以讓應用程序具備自動提供特定數據類型的功能。例如,一個 mailto: 鏈接可以使用 DataType.EmailAddress 數據類型創建,在支持 Html5 的瀏覽器中並且日期選擇器可以提供 DataType.Date 的值。DataType 特性向瀏覽器發送 HTML 5 標簽 data- (pronounced data dash)。DataType 特性 無法 提供任何驗證。

DataType.Date 不指定日期的顯示格式。默認情況下,數據字段默認的顯示格式基於服務器的 CultureInfo 設置來決定的。

DisplayFormat 特性被用來格式化日期:

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

ApplyFormatInEditMode 用來指定格式是否應用到文本框編輯。(你可能不希望在某些字段中使用這個功能——例如,對於貨幣值,你可能不希望在文本框中對貨幣符號進行編輯。)

你可以直接使用 DisplayFormat 特性本身,但是更好的方式是建議使用 DataTypeDataType 特性僅僅傳遞數據的語義,並不會通知瀏覽器如何呈現,如果不使用 DisplayFormat 有以下好處:

  • 瀏覽器可以啟用 HTML5 功能(例如顯示日歷控件,設置本地化的貨幣符號,電子郵件中的鏈接,等等)。
  • 默認情況下,瀏覽器將基於你的 本地環境 使用正確的格式渲染數據。
  • DataType 特性可以使 MVC 選擇正確的字段模板來呈現數據(比如 DisplayFormat 如果單獨使用 string 模板)。更多信息,請參考 Brad Wilson 的 ASP.NET MVC 2 模版。(盡管是為 MVC 2編寫的, 文章依然適用於當前的 ASP.NET MVC 版本。)

注意
Range 特性同時使用 DateTime 類型的時候 jQuery 驗證無法生效。例如,下面的代碼將始終顯示客戶端驗證錯誤,即使日期在指定范圍內:

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

你需要禁止在 DateTime 上使用 Range 特性來進行 JQuery 日期驗證。在你的模型中編譯具體日期通常不是一個好的做法,所以不建議在 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)] //手工高亮
    public decimal Price { get; set; }

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

在下一個系列里面, 我們會重新審視應用程序,為自動生成的 Details 以及 Delete 方法做一些提升。

附錄資源

返回目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM