iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
1
Modern Web

大內魔術 Blazor - 誰說前端一定要寫JS系列 第 10

表單魔術 - 驗證技巧

  • 分享至 

  • xImage
  •  

今天要來介紹的是表單的驗證,畢竟不可能讓每一份表單都交由後端來驗證並返還結果,往往都會由前端來排除最基本的使用者操作失誤,如說好密碼要大小寫與數字兼具,卻只給小寫加數字,又或者填寫日期時,結束日期在開始日期之前,諸如此類的問題。

當然這並不是說後端不用""檢查,該做的事情還是要做,只是前端先阻擋最基本的錯誤,可以省下許多的 http 請求。所以今天要帶大家透過資料註解來撰寫簡單的畫面驗證,並且客製化自己的驗證。


資料註解(DataAnnotations)

又稱驗證屬性(Attribute),可以讓你指定模型屬性(Property)的驗證規則。

以下介紹幾個比較常用的驗證屬性:

  • Required: 該欄位為必填。

  • StringLength(int maximun): 該字串欄位長度限制,最小值是可選參數,建構式只要求最大值,以限制長度五到十的字串為例:

    [StringLength(10, MinimumLength = 5)]
    
  • Range(int minimun, int maximun): 該數值欄位的範圍限制,以限制數字區間為一到兩百為例:

    [Range(1, 200)]
    
  • RegularExpression(string pattern): 該欄位需符合特定的正規表達式,以簡單的台灣手機格式為例:

    [RegularExpression(@"^09\d{8}$")]
    
  • EmailAddress: 該欄位需為電子信箱格式。

  • Url: 該欄位需為 URL 格式。

當然不只這些,想看完整的話可以到System.ComponentModel.DataAnnotations 命名空間觀看。

建立自訂驗證屬性

若內建的驗證屬性無法達成你的需求時,我們可以建立自訂驗證屬性,只需要繼承 ValidationAttribute 並且覆寫 IsValid 方法即可。

IsValid 方法有兩種多載:IsValid(object value)IsValid(object value, ValidationContext validationContext)

  • value 該屬性的值。

  • validationContext 驗證的上下文,並可以透過 ObjectInstance 取得驗證實例後取得其他欄位的值。

而我們,只需要根據情境覆寫一個方法即可,若兩個都覆寫,則 IsValid(object value) 會是失效的那個。

客製化驗證通常都是針對不同欄位間對彼此的影響來決定驗證內容,而這邊就以一個簡單的例子說明,如果某欄位在某身分時必填,就可以寫成:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
  var user = (UserViewModel)validationContext.ObjectInstance;

  if (user.UserType == UserType.member && (value is null || string.IsNullOrEmpty(value.ToString())))
  {
    return new ValidationResult(base.ErrorMessage ?? "此欄位會員必填!");
  }

  return ValidationResult.Success;
}

這邊要提一點,我回傳錯誤訊息時,使用了base.ErrorMessage ?? "此欄位會員必填!",讓外部使用時也能透過設定 ValidationAttributeErrorMessage 來客製化訊息,而所有的內建驗證屬性也都繼承於 ValidationAttribute,所以都能夠使用 ErrorMessage 屬性來客製化錯誤訊息,也就是:

[Required(ErrorMessage = "此欄位為必填!")]

當你撰寫好客製化驗證後,會發現(可能吧?)在顯示錯誤訊息時,明明在 <ValidationSummary /> 有正確顯示錯誤,而 <ValidationMessage For="@(()=>model.PropertyName)" /> 卻一點訊息都沒有!

因為在傳回 ValidationResult 時,要指定是哪些屬性名稱的錯誤,否則就會對應不到,所以我們的傳回值應該是:

new ValidationResult(base.ErrorMessage ?? "此欄位會員必填!", new[] { validationContext.MemberName })

第二個參數是屬性名稱陣列,可以透過 validationContext.MemberName 來取得該屬性的名稱,若裡面放了別的屬性名稱,別的屬性就會出現同樣的錯誤,是不是很神奇呀?例如結束時間必需在開始時間之後這類訊息,往往都只能擺在一個屬性上,但其實對於使用者來說,調整兩個屬性的其中一個就好,也就是並非單一個錯誤,而是兩個都是錯誤才對吧?若想看此類驗證器,我有撰寫一個驗證器在範例程式碼 - day10

最後一點是,IsValid(object value) 的傳回值是 bool,而不是 ValidationResult,所以並無上述問題,且 ValidationMessage 能正確取得該屬性名稱的錯誤訊息。


以上就是透過資料註解來進行資料驗證,與客製化驗證器的方法。

感謝大家的閱讀,我們明天見。

參考資料
內建屬性
DataAnnotations


上一篇
表單魔術
下一篇
表單魔術 - 內建元件道具
系列文
大內魔術 Blazor - 誰說前端一定要寫JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言