ASP.NET MVC 3 豬走路範例(2)裡介紹過ASP.NET MVC可以識別Model屬性(Property)上的DataAnnotation ValidationAttribute,例如: [Required][Range(…)],自動在表單輸入介面加上檢核函數,更新資料時也可用同一邏輯進行伺服器資料檢核,不用再像以前Client、Server各寫一次,也不容易因開發人員疏忽而錯放無效資料,十分方便可靠。

遇到個需求,在Console程式中引用為ASP.NET MVC開發的Model DLL,在修改完Model的屬性內容後,也想用Model上各屬性所標註的[Required][Range()] ValidationAttribute進行資料驗證。

System.ComponentModel.DataAnnotations內建了Validator Class可以幫我們實現這個理想,我整理成簡單的程式範例:

using System;
using System.Collections.Generic;
using Autofac;
using System.ComponentModel.DataAnnotations;
 
namespace AutofacLab
{
    class Program
    {
        static void Main(string[] args)
        {
            BooModel boo = new BooModel(); //故意不給Name
            ShowValidationResult(boo);
 
            boo.Name = "Jeffrey Lee"; //故意讓Name過長
            boo.Score = 65535; //故意讓數字超出範圍
            ShowValidationResult(boo);
 
            boo.Name = "Jeffrey";
            boo.Score = 32767;
            ShowValidationResult(boo);
 
            Console.Read();
        }
 
        static void ShowValidationResult(BooModel boo)
        {
            ValidationContext vldCtx =
                new ValidationContext(boo, null, null);
            List<ValidationResult> errors =
                new List<ValidationResult>(); //檢核錯誤會被放入集合
            //注意第四個參數,要填true,才會檢核Required以外的ValidationAttribute
            //參數名稱(validateAllProperties)有誤導之嫌
            //已有網友在Connect反應: http://goo.gl/zllLw
            bool succ = Validator.TryValidateObject(boo, vldCtx, errors, true);
            Console.WriteLine("Boo {{ Name:{0} Score:{1} }}", 
                boo.Name, boo.Score);
            Console.WriteLine("Pass? {0}", succ);
            foreach (ValidationResult r in errors)
                Console.WriteLine(" - Error: {0}", r.ErrorMessage);
        }
 
    }
 
    class BooModel
    {
        [Required(ErrorMessage = "Name is required")]
        [StringLength(8, ErrorMessage = "Max length = 8")]
        public string Name { get; set; }
        
        [Range(0, 32767, ErrorMessage = "Range = 0-32767")]
        public int Score { get; set; }
    }
}

執行結果為:

Boo { Name: Score:0 }
Pass? False
- Error: Name is required
Boo { Name:Jeffrey Lee Score:65535 }
Pass? False
- Error: Max length = 8
- Error: Range = 0-32767
Boo { Name:Jeffrey Score:32767 }
Pass? True

補充一點,測試這段程式時,踩到一枚小地雷。

經測試,想要完整觸發所有的ValidationAttribute,得使用 Validator.TryValidateObject Method (Object, ValidationContext, ICollection<ValidationResult>, Boolean),並在第四個參數傳入true,才會檢核[Required]以外的ValidationAttribute,這跟參數名稱(validateAllProperties)與文件所說"如果 validateAllProperties 設定為 true,此方法會驗證物件之屬性 (Property) 全部的值。"有點出入,已有網友回報Microsoft Connect此一問題,官方的回覆也證實此點(Thanks for the suggestion. Unfortunately now with named parameters as a feature in the compiler even renaming a parameter can become a breaking change. Due to this will have to leave the property named as it is.) 在應用時要留意。


Comments

# by David.net

又學到一招了 之前我還自己寫檢查 DataAnnotations 的語法 卻沒發現原來有現成的工具阿 昏了~~ 謝謝

# by jain

這看起來也可用在一般的AP,不只ASP.NET嗎?

# by Jeffrey

to jain, Yes, DataAnnotations被歸在System.ComponentModel,並不是ASP.NET的專利,例如在Silverlight裡也可應用,而文中的範例是用Console Application來跑的。

Post a comment