ASP.Net Core MVC 之模型驗證

在我們日常的表單中,我們總需要寫很多的驗證,這個是避免不了的,不寫,安全上過不去,寫了,又很繁瑣。

我們不僅前端要寫驗證,後端也需要寫驗證,才能杜絕非法數據入侵。

例如下面的代碼:在服務層的保存方法中進行參數驗證

 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進行實體間映射到數據庫實體。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章