1. 程式人生 > >[C#.NET 拾遺補漏]09:資料標註與資料校驗

[C#.NET 拾遺補漏]09:資料標註與資料校驗

資料標註(Data Annotation)是類或類成員新增上下文資訊的一種方式,在 C# 通常用特性(Attribute)類來描述。它的用途主要可以分為下面這三類: - 驗證 Validation:向資料新增驗證規則 - 顯示 Display:指定資料如何呈現給使用者 - 模型 Modelling:新增關於用法和與其它類的關係資訊 下面是一個用來驗證和展現使用者資訊的一個 Model: ```cs class Kid { [Range(0, 18)] // 年齡不能超過18歲,不能為負數 public int Age { get; set; } [StringLength(MaximumLength = 50, MinimumLength = 3)] // 名稱的長度不能超過 50,不能小於 3 public string Name { get; set; } [DataType(DataType.Date)] // 生日將作為日期展示 (不帶時間) public DateTime Birthday { get; set; } } ``` 資料標註的顯示用途主要在早期的 ASP.NET 和 ASP.NET MVC 等框架中使用。例如,在 ASP.NET MVC 中,Razor 引擎會根據 Model 屬性的 DataType 特性動態生成不同型別的表單元素。不過,現在這類用途除了 WPF(比如 `EditableAttribute`)已經過時很少用了。 資料標註用來驗證資料的合法性是最常見的用法,在 ASP.NET Core/Mvc 中,資料作為表單 Model 提交時,框架會對 Model 資料自動進行校驗,也可以手動呼叫 `ModelState.IsValid()` 來判斷資料是否合法。 ## 自定義校驗特性 自定義一個校驗特性很簡單,建立一個繼承 `ValidationAttribute` 的類,然後重寫它的 `IsValid` 方法。示例: ```cs [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public class EvenNumberAttribute : ValidationAttribute { public override bool IsValid(object input) { if (input == null) return false; if (!int.TryParse(input.ToString(), out int val)) return false; return val % 2 == 0; } } ``` 然後這個特性可以這麼用: ```cs public class Model { [EvenNumberAttribute(ErrorMessage = "數字必須是偶數")] public int MyNumber { get; set; } } ``` 除了這自定義校驗的方式,C# 還提供了一個 `CustomValidation` 特性,也是用來自定義資料校驗的,它是通過反射的方式來實現的。示例: ```cs public class Model { [CustomValidation(typeof(MyCustomValidation), "IsNotEvenNumber")] public int MyNumber { get; set; } } public static class MyCustomValidation { public static ValidationResult IsNotEvenNumber(object input) { var result = new ValidationResult("數字必須是偶數"); if (input == null || !int.TryParse(input.ToString(), out int val)) return result; return val % 2 == 0 ? ValidationResult.Success : result; } } ``` C# 內建了很多常用資料校驗特性類,比如最常用的 `RequiredAttribute`、`StringLengthAttribute`、`RangeAttribute` 等。 ## 手動執行資料校驗 大多數時候,資料校驗都是由框架(如 ASP.NET Core)幫我們做了,但有時候我們想手動執行校驗資料怎麼做呢?簡單說,使用 `Validator` 類即可,但也不是想像的那麼直接。資料校驗需要提供檢驗的資訊,比如校驗規則、需要校驗的屬性及未通過顯示的錯誤資訊等,而這些需要由另一個類來從待校驗的例項中提取作為上下文,它是 `ValidationContext`,所以需要先建立 `ValidationContext` 物件: ```cs ValidationContext vc = new ValidationContext(objectToValidate); ``` 建立好這個上下文物件就可以對資料進行多種方式的校驗了,比如校驗物件的所有屬性: ```cs ValidationContext vc = new ValidationContext(objectToValidate); ICollection results = new List(); bool isValid = Validator.TryValidateObject(objectToValidate, vc, results, true); ``` 也可以只校驗物件的指定屬性: ```cs ValidationContext vc = new ValidationContext(objectToValidate); ICollection results = new List(); bool isValid = Validator.TryValidatePropery(objectToValidate.PropertyToValidate, vc, results, true); ``` 返回值 isValid 表示是否所有資料都驗證通過,驗證失敗的資訊會放到 results 結果集。 看到這,我覺得手動執行校驗還是有點麻煩,建立 `ValidationContext` 物件這一步如果也封裝在 `Validator` 類的方法內,豈不是簡潔