[.NET] 使用ValidationContext快速進行模型資料的驗證

在進行WebAPI功能開發的時候,一般傳統的驗證資料是否合法的方式,都是透過if/else的方式進行判斷
若是使用ValidationContext,就可以省去很多自行撰寫程式碼的工作

要使用ValidationContext的驗證方式很簡單,我先用一個簡單的例子來說明就可以呈現所需要的結果

1.首先先在專案中建立一個新的模型檔案,並在模型檔案中加入下面的程式碼

public class ValidModels
{
    /// <summary>
    /// 輸入資料的模型
    /// </summary>
    public class ValidInfoQuery
    {
        [Required]
        public string Name { get; set; }
        public string Tel { get; set; }
        public string Address { get; set; }
        [Required]
        [Range(1, 130)]
        public int Age { get; set; }
        [Required]
        public DateTime Birthday { get; set; }
    }

    /// <summary>
    /// 回傳驗證結果的模型
    /// </summary>
    public class ValidInfoResult
    {
        public bool IsValid { get; set; }
        public List<ValidItem> List { get; set; }
        public class ValidItem
        {
            public IEnumerable<string> Field { get; set; }
            public string Message { get; set; }
        }
    }
}

在這個模型中,我們定義了要輸入的資料模型,以及要回傳的模型定義,在輸入的模型ValidInfoQuery中,特別在"Name"、"Age"、"Birthday"三個欄位中,加上[Required]的屬性。並且在"Age"的欄位中,加入[Range(1, 130)]的屬性,代表Age的合法值在1到130之間

2.接著加入一個新的控制器 "ValidController.cs",加入一個POST的方法,並將剛剛新增的模型,分別放入Input以及Output的參數

public class ValidController : ApiController
{
    /// <summary>
    /// 執行資料寫入的Post動作
    /// </summary>
    /// <param name="query"></param>
    public Models.ValidModels.ValidInfoResult Post(Models.ValidModels.ValidInfoQuery query)
    {

    }
}

3.一般傳統進行輸入資料驗證的方式,會採用下面的方式進行驗證

// 傳統欄位驗證的寫法

// 驗證Name欄位
if (string.IsNullOrEmpty(query.Name))
{
    result.IsValid = false;
    result.List.Add(new Models.ValidModels.ValidInfoResult.ValidItem()
    {
        Field = new List<string> { "Name" },
        Message = "Name欄位必填"
    });
}

// 驗證Age欄位
if (query.Age > 130 || query.Age < 1)
{
    result.IsValid = false;
    result.List.Add(new Models.ValidModels.ValidInfoResult.ValidItem()
    {
        Field = new List<string> { "Age" },
        Message = "Age欄位必須在1與130之間"
    });
}

但是這樣的寫法,一但Input模型的欄位增加的話,程式碼也會相對的增加。也會影響程式碼的效率。所以我們將驗證的方式更改一下,改為ValidationContext進行驗證

// 使用ValidationContext的驗證物件
// 定義ValidationContext的驗證物件
var context = new ValidationContext(query);

// 定義進行Validation回傳的訊息
var validationResults = new List<ValidationResult>();

// 進行驗證動作
bool isValid = Validator.TryValidateObject(query, context, validationResults, true);

// 將驗證結果進行處理,並回傳到指定的回傳物件中
result.IsValid = isValid;
result.List = validationResults.Select(c => new Models.ValidModels.ValidInfoResult.ValidItem()
                                {
                                    Field = c.MemberNames,
                                    Message = c.ErrorMessage
                                })
                                .ToList();

從上面的程式碼可以很清楚的看到,只要定義出一個ValidationContext物件,並將要驗證的模型資料傳入,就可以在TryValidateObject的方法中,將所有資料不合法的欄位進行驗證並得到結果

4.程式碼完成後,我們實際執行剛剛的程式內容,並透過Swagger進行資料的輸入。其中Name的欄位以及Age的欄位我刻意輸入了不合法的內容按下"Try it"之後,得到的結果如下圖所示可以看到,在結果的顯示上,很清楚的列出"Name"與"Age"兩個欄位是驗證失敗的,也顯示了為什麼發生錯誤的訊息內容

透過ValidationContext的驗證方式,除了可以很快的完成模型資料的合法性驗證外,也可以大量的減少撰寫驗證資料的程式碼,提升程式效率與開發速度

範例程式下載
https://github.com/madukapai/maduka-WebAPI

參考資料
How to manually validate a model with attributes?
MinValue & MaxValue attribute for properties
ValidationContext Class