2021年6月21日 星期一

ASP.NET WebApi ModelState.IsValid 無法發揮作用時的補救方法

有幸遇到此特殊情境,很特別的經驗,一定要動手紀錄一下,了解之後也不是不能解,

只是,為何要這樣設計呢?也許當時前人評估後這樣效益比較高...,前人的智慧,

博大精深..,凡人無法擋...,祖產...



為何 ModelState.IsValid 無法發揮作用?先說說,會如何應用此特色,由於需要驗證

傳送過來的Request Model ,所以會掛上資料驗證特性,這樣可以方便管理參數設定

,減少污染 body code,至於DataAnnotations Attrubute ,如設定為必填欄位,或是

限制內容長度,等等,如下圖


只是,這次怎麼使用 ModelState.IsValid 都只會回傳 false,這狀況拖住了我;


經過抽絲剝繭,發現原來api 的傳送接收兩端有訂定資料都要加解密,故接收端設計

時,可能為了有效的管理,自訂了attribte 來處理加解密,再將解密的資料指定給

RequestModel,以下逐步


Action 設計

上圖,可看出設計一個 Test Action 方法,並且掛上 ApiValidAttribute,且方法有

CustomRequest 參數傳入,判斷若驗證不通過,則回傳「資料格式有誤」文字



ApiValid



上圖中,為簡化步驟實際更複雜,在17、18行,模擬取得 request 內容且正常解密,

在20、21行,將資料反序列化塞回原本的 action


實際發生如下

首先postman 模擬請求


server 端接收到請求,偵錯內容如下



上圖可以看到,request 已經在 ApiValid 的 OnActionExcuting 方法中,被換成對應的值,

且相關欄位也都符合驗證條件,得到的驗證結過卻是 false


其實,冷靜思考後發現很明顯的,一開始的 postman 就是傳加密 data ,後面才是解密

後塞值,這之前就已經 Valid 沒有過啦,所以後續怎麼改都沒用;除非在解密塞值後,

再跑一次驗證...,若此時相關底層類別無法修改,那就只能繞道處理了



接著,我們需要設計再次驗證的程式碼,直接在原本的 Controller 類別下設計,或是

另外寫BaseController,讓現有的繼承,以下是設計




上圖可看出,原本26 行使用 ModelState.IsValid 取得驗證結果的地方,改呼叫自訂的方法 Validate ,

而該方法中, 37 行,new validationContext 時傳入 model,38 行,執行驗證,

43行,將結果回傳,回到 28 行,若此時驗證有問題,會取串列中第一個錯誤來顯示


調整塞值的地方,如下圖,故意讓驗證錯誤發生,將 Name 欄位設定為空字串,期許發生錯誤


錯誤發生


以上,本著還原案發經過,訴說著當下不能只有我遇到的心情



參考:

 

沒有留言:

張貼留言