在我們日常的表單中,我們總需要寫很多的驗證,這個是避免不了的,不寫,安全上過不去,寫了,又很繁瑣。
我們不僅前端要寫驗證,後端也需要寫驗證,才能杜絕非法數據入侵。
例如下面的代碼:在服務層的保存方法中進行參數驗證
var jsonCode = new JsonCode { code = -1, msg = "校驗失敗" }; if (dtoModel.UserId.IsNullOrEmpty()) { jsonCode.msg = "請填寫用戶ID!"; return jsonCode; } if (string.IsNullOrWhiteSpace(dtoModel.CommitmentFileUrl)) { jsonCode.msg = "請提交科研誠信承諾書!"; return jsonCode; } if (dtoModel.CompanyName.IsNullOrEmpty()) { jsonCode.msg = "請填寫技術轉移機構名稱!"; return jsonCode; } if (!Regex.IsMatch(dtoModel.CompanyName, @"^[\S\s]{4,20}$")) { jsonCode.msg = "請輸入4-20個字的技術轉移機構名稱"; return jsonCode; } if (dtoModel.CreditCode.IsNullOrEmpty()) { jsonCode.msg = "請填寫統一社會信用代碼!"; return jsonCode; }
當表單字段多的時候,這個就寫得很長,而且發佈時候寫一次,審覈的後臺也需要再寫一次。是不是很繁瑣。
下面就進入主題,介紹模型驗證的應用(微軟自帶):
引入命名空間:System.ComponentModel.DataAnnotations
基礎驗證規則,請參考官方文檔:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-6.0
這裏僅講解在項目中怎麼應用和自定義顯示驗證信息
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; namespace 模型驗證.Models { [Serializable] public class CreateUserDto { [Required(ErrorMessage ="請填寫姓名")] public string Name { get; set; } } }
我們只需在實體上定義各個字段的校驗規則,接下來就是在控制器中應用
public IActionResult Index(CreateUserDto user)//參數必須以對象形式,一般是createDto,即對應表達的字段內容。 { if(!ModelState.IsValid) { foreach(var item in ModelState.Values) //循環驗證每個對象 { if (item.ValidationState == ModelValidationState.Invalid) //判斷是否是模型綁定 { return new ContentResult(){Content= item.Errors.FirstOrDefault().ErrorMessage }; //返回第一個字段的錯誤信息 } } } return View(); }
運行起來:
顯示驗證信息。
如果我們加上Name參數呢,驗證通過,顯示頁面。
以上是一個簡單的例子,講了在哪裏定義驗證規則,以及怎麼獲取自定義的驗證信息來顯示。
但是在實際項目中,我們不可能在每個控制器中去寫這麼一串代碼輸出異常。
實際項目中,我們需要用到過濾器了,下面定義一個過濾器:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace 模型驗證.Models { public class ValidateFilter : IActionFilter { public void OnActionExecuted(ActionExecutedContext context) { } public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { string msg = ""; foreach (var item in context.ModelState.Values) { if (item.ValidationState == ModelValidationState.Invalid) { if (item.Errors != null && item.Errors.Any()) { msg = item.Errors.FirstOrDefault().ErrorMessage; } break; } } context.Result = new JsonResult(new { code=-1,msg=msg}); //以json形式返回,在項目中也可以根據需要處理,比如ajax請求的,返回json,否則返回文本內容 } } } }
接着在startup.cs中應用過濾器:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(options=> { options.Filters.Add<ValidateFilter>(); }); }
這時候,控制器中的代碼就可以去掉了
public IActionResult Index(CreateUserDto user) { return View(); }
運行起來,就會執行過濾器的驗證規則進行驗證了。
這樣大大減少了我們後端做驗證的複雜度。
有幾點需要注意:
1:對於驗證規則不支持的,那隻能在業務端自行判斷,判斷後輸出。
2:該種方式,實現了業務端在表單驗證中的無感,不需要去關注驗證過程,大大提升這方面的效率。
3:在dto上,建議不用共用dto,表單輸入創建一個CreateXXXDto,輸出創建一個XXXDto。 哪怕一模一樣也不要去共用,後期應對變化會靈活些。
對於CreateDto中一般不定義主鍵Id,而是跟表單UI中內容一致的。利用automapper進行實體間映射到數據庫實體。