

Web API 2 筆記 - 資料物件驗證
source link: https://blog.darkthread.net/blog/webapi2-post-validation/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Web API 2 筆記 - 資料物件驗證
2019-05-01 09:35 AM | 5 | 6,990 |
介紹 ASP.NET WebAPI 2 驗證傳入參數資料物件的簡便做法。
假設我們有個需求,要寫一個 Web API 方法集中蒐集排程作業執行 Log 寫入資料庫,為符合 Schema 要求,接收參數時需檢查 NOT NULL 欄位必須有值,字串長度不能超過欄位 NVARCHAR(N) 長度... 等等,避免出錯。
將範例更具體化,這個 Web API 方法需傳入 TaskName(作業名稱)、Action(動作)、EventType(事件別,例如:開始執行、執行成功或失敗)、Message(訊息),而 TaskName、Action 不可空白且有長度限制,最直白不花腦筋的寫法是將以上欄位一一宣告成方法變數,再寫 if 加上檢查,例如:
public void Add(string taskName, string action, string eventType, string message)
{
var errors = new List<string>();
if (string.IsNullOrEmpty(taskName))
errors.Add("taskName 不可空白");
else if (taskName.Length > 16)
errors.Add("taskName 過長");
//...省略...
}
母湯啊母湯!
在 ASP.NET MVC 或 Web API 有打火機可用,不要傻傻鑽木取火啊~
較優雅的做法是宣告資料物件,再用 System.ComponentModel.DataAnnontations 命名空間提供的 [Required]、[StringLength] Attribute 指定屬性驗證要求。在本例我們定義成 TaskLogEntity 型別,宣告 TaskName、Action 不可空白且最大長度分別為 16 及 32。至於 EventType 事件別則另外定義列舉型別,限制 Start、Succ、Fail 三種選擇:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.ComponentModel.DataAnnotations;
namespace WebApiDemo.Models
{
/// <summary>
/// 作業記錄物件
/// </summary>
public class TaskLogEntity
{
/// <summary>
/// 發生時間
/// </summary>
public DateTime LogTime { get; set; } = DateTime.Now;
/// <summary>
/// 作業名稱
/// </summary>
[Required]
[StringLength(16)]
public string TaskName { get; set; }
/// <summary>
/// 動作
/// </summary>
[Required]
[StringLength(32)]
public string Action { get; set; }
/// <summary>
/// 事件別
/// </summary>
public EventTypes EventType { get; set; }
/// <summary>
/// 訊息
/// </summary>
public string Message { get; set; }
}
/// <summary>
/// 事件別列舉
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum EventTypes
{
/// <summary>
/// 開始執行
/// </summary>
Start,
/// <summary>
/// 執行成功
/// </summary>
Succ,
/// <summary>
/// 失敗
/// </summary>
Fail
}
}
補充幾點:
- [MaxLength] 與 [StringLength] 都可限定字串屬性最大長度,但 StringLength 才支援客戶端驗證。(參考:You Have Chosen Poorly - MaxLength vs StringLength)
- 在列舉型別加註 [JsonConverter(typeof(StringEnumConverter))] 的用意是當 POST Json 傳入資料時,Json.NET 可直接將 eventType 的 "Start"、"Succ"、"Fail" 文字轉為 EventTypes 型舉型別。延伸閱讀:Json.NET技巧兩則: 忽略屬性及列舉轉字串
- [Required]、[StringLength] 亦可自訂顯示欄位名稱及錯誤訊息,詳情可參考舊文:ASP.NET MVC 3 豬走路範例 (2)
- 若現成驗證規則無法滿足需求,自訂也不是難事。有兩個方向,一個是自訂 ValidationAttribute 子型別加註在要驗證的屬性上;若驗證規則較複雜涉及多個屬性,可選擇在 Entity 類別實作 IValidatableObject 介面,在 Validate(ValidationContext validationConext) 方法執行自訂檢查邏輯。參考:自訂 ValidationAttribute、IValidationObject
做好 Entity 類別,剩下的交給 ASP.NET Web API 2 的資料繫結機制就可以了。範例方法如下:
/// <summary>
/// 新增作業執行記錄
/// </summary>
/// <param name="entity"></param>
[HttpPost]
public HttpResponseMessage Add([FromBody]TaskLogEntity entity)
{
//若資料驗證未過,傳回錯誤訊息
if (!ModelState.IsValid)
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
entity.LogTime = DateTime.Now;
//TODO: 將 Entity 寫入資料庫
//TaskLogDataHelper.Insert(entity);
//成功時傳回OK
return Request.CreateResponse(HttpStatusCode.OK);
}
ASP.NET Web API 2 的資料繫結機制會將 POST Body 傳入的 JSON 轉換成 TaskLogEntity 物件,而 ModalState.IsValid 為資料驗證成功失敗旗標,false 表驗證失敗,要顯示哪些驗證條件失敗的方法很簡單,HttpRequestMesage 有個 CreateErrorResponse(HttpStatusCode, ModelStateDictionary) 方法,將 ModelState 當成參數傳進去,呈現錯誤訊息的事就交給 ASP.NET 處理,不用我們操煩。
來實測一下。借用 NSwag Swagger UI,故意輸入無效內容,TaskName 過長、Action 為 null、EventType 給無效值。如下圖所示,Web API 2 一如預期傳回 HTTP Status 400 BadRequest,並一一列出無效欄位跟錯誤訊息,很酷吧?
下一篇再來聊聊 GET 或 Uri 方式傳入參數時的資料驗證。
【延伸閱讀】
</div
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK