有幸遇到此特殊情境,很特別的經驗,一定要動手紀錄一下,了解之後也不是不能解,
只是,為何要這樣設計呢?也許當時前人評估後這樣效益比較高...,前人的智慧,
博大精深..,凡人無法擋...,祖產...
為何 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 欄位設定為空字串,期許發生錯誤
錯誤發生
以上,本著還原案發經過,訴說著當下不能只有我遇到的心情
參考:
https://visualstudiomagazine.com/articles/2015/06/19/tdd-asp-net-mvc-part-4-unit-testing.aspx
https://docs.microsoft.com/zh-tw/dotnet/api/system.componentmodel.dataannotations?view=net-5.0
https://andrewlock.net/creating-an-empty-guid-validation-attribute/
沒有留言:
張貼留言