ASP.NET Core搭建多層網站架構【8.1-使用ViewModel注解驗證】


2020/01/29, ASP.NET Core 3.1, VS2019

摘要:基於ASP.NET Core 3.1 WebApi搭建后端多層網站架構【8.1-使用ViewModel注解驗證】
使用ViewModel注解驗證字段合法性,將ViewModel的字段驗證寫在了ViewModel類內部

文章目錄

此分支項目代碼

本章節介紹了使用ASP.NET Core自帶的注解驗證前端提交的參數

確認MS.Models類庫已引用MS.Component.JwtMS.DbContexts兩個項目

添加業務操作枚舉和返回值定義

MS.WebCore類庫中新建Core文件夾,在該文件夾中新建ExecuteResult.csExecuteType.cs類:

ExecuteResult.cs

namespace MS.WebCore.Core
{
    /// <summary>
    ///  執行返回結果
    /// </summary>
    public class ExecuteResult
    {
        public virtual ExecuteResult Set(bool isSucceed, string message)
        {
            IsSucceed = isSucceed;
            Message = message;
            return this;
        }
        /// <summary>
        /// 設定錯誤信息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public virtual ExecuteResult SetFailMessage(string message)
        {
            return Set(false, message);
        }
        public virtual ExecuteResult SetFail()
        {
            return Set(false, string.Empty);
        }
        public ExecuteResult(bool isSucceed, string message)
        {
            Set(isSucceed, message);
        }
        /// <summary>
        /// 如果是給字符串,表示有錯誤信息,默認IsSucceed=false
        /// </summary>
        /// <param name="message"></param>
        public ExecuteResult(string message)
        {
            Set(false, message);
        }
        /// <summary>
        /// 如果是空的,沒有信息,默認IsSucceed=true
        /// </summary>
        public ExecuteResult()
        {
        }
        /// <summary>
        /// 執行是否成功
        /// 默認為True
        /// </summary>
        public bool IsSucceed { get; set; } = true;
        /// <summary>
        /// 執行信息(一般是錯誤信息)
        /// 默認置空
        /// </summary>
        public string Message { get; set; } = string.Empty;
    }
    /// <summary>
    /// 執行返回結果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ExecuteResult<T> : ExecuteResult
    {
        public ExecuteResult<T> Set(bool isSucceed, string message, T result)
        {
            IsSucceed = isSucceed;
            Message = message;
            Result = result;
            return this;
        }
        public ExecuteResult<T> SetData(T data)
        {
            return Set(true, string.Empty, data);
        }
        public new ExecuteResult<T> SetFail()
        {
            return Set(false, string.Empty, default);
        }
        /// <summary>
        /// 設定錯誤信息
        /// 如果T正好也是string類型,可能set方法會存在用錯的時候,所以取名SetMessage更明確
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public new ExecuteResult<T> SetFailMessage(string message)
        {
            return Set(false, message, default);
        }
        public ExecuteResult()
        {
        }
        public ExecuteResult(string message)
        {
            Set(false, message);
        }
        public ExecuteResult(bool isSucceed, string message)
        {
            Set(isSucceed, message);
        }
        public ExecuteResult(T result)
        {
            SetData(result);
        }

        public T Result { get; set; }
    }
}

這個類是定義了業務相關方法調用的返回值結果,包含了是否成功、錯誤信息,也可以拓展泛型夾帶其他內容

ExecuteType.cs

namespace MS.WebCore.Core
{
    /// <summary>
    /// 表示操作數據庫類型
    /// </summary>
    public enum ExecuteType
    {
        /// <summary>
        /// 讀取資源
        /// </summary>
        Retrieve,
        /// <summary>
        /// 創建資源
        /// </summary>
        Create,
        /// <summary>
        /// 更新資源
        /// </summary>
        Update,
        /// <summary>
        /// 刪除資源
        /// </summary>
        Delete
    }
}

這個枚舉定義了業務操作的類型,對應數據庫的CRUD

新建ViewModel

MS.Models類庫中新建ViewModel文件夾,在該文件夾中新建RoleViewModel.cs類:

using MS.DbContexts;
using MS.Entities;
using MS.UnitOfWork;
using MS.WebCore.Core;
using System.ComponentModel.DataAnnotations;

namespace MS.Models.ViewModel
{
    public class RoleViewModel
    {
        public long Id { get; set; }
        [Display(Name = "角色名稱")]
        [Required(ErrorMessage = "{0}必填")]
        [StringLength(16, ErrorMessage = "不能超過{0}個字符")]
        [RegularExpression(@"^[a-zA-Z0-9_]{4,16}$", ErrorMessage = "只能包含字符、數字和下划線")]
        public string Name { get; set; }
        [Display(Name = "角色顯示名")]
        [Required(ErrorMessage = "{0}必填")]
        [StringLength(50, ErrorMessage = "不能超過{0}個字符")]
        public string DisplayName { get; set; }
        [Display(Name = "備注")]
        [StringLength(4000, ErrorMessage = "不能超過{0}個字符")]
        public string Remark { get; set; }

        public ExecuteResult CheckField(ExecuteType executeType, IUnitOfWork<MSDbContext> unitOfWork)
        {
            ExecuteResult result = new ExecuteResult();
            var repo = unitOfWork.GetRepository<Role>();

            //如果不是新增角色,操作之前都要先檢查角色是否存在
            if (executeType != ExecuteType.Create && !repo.Exists(a => a.Id == Id))
            {
                return result.SetFailMessage("角色不存在");
            }

            //針對不同的操作,檢查邏輯不同
            switch (executeType)
            {
                case ExecuteType.Delete:
                    //刪除角色前檢查角色下還沒有員工
                    if (unitOfWork.GetRepository<User>().Exists(a => a.RoleId == Id))
                    {
                        return result.SetFailMessage("還有員工正在使用該角色,無法刪除");
                    }
                    break;
                case ExecuteType.Update:
                    //如果存在Id不同,角色名相同的實體,則返回報錯
                    if (repo.Exists(a => a.Name == Name && a.Id != Id))
                    {
                        return result.SetFailMessage($"已存在相同的角色名稱:{Name}");
                    }
                    break;
                case ExecuteType.Create:
                default:
                    //如果存在相同的角色名,則返回報錯
                    if (repo.Exists(a => a.Name == Name))
                    {
                        return result.SetFailMessage($"已存在相同的角色名稱:{Name}");
                    }
                    break;
            }
            return result;//沒有錯誤,默認返回成功
        }
    }
}

說明

  • Display是該字段的顯示名稱
  • Required注解標記該字段必填,不可為空
  • StringLength注解標記該字段長度
  • RegularExpression注解是正則表達式驗證
  • 還有個Range注解特性是驗證值的范圍的,這里沒用到

除了注解,我把對象字段的邏輯驗證寫在了ViewModel中,沒有把它放在業務層是因為,我認為對象字段本身的合法性和對象是強相關的,就和注解直接寫在ViewModel中而不是Service中一樣,所以把字段的驗證也寫在了ViewModel里

對象字段的邏輯驗證我區分了操作類型,新增時檢查角色名是否有重復;刪除時檢查是否還有用戶使用該角色;更新時檢查用戶提交的角色是否存在於數據庫中

新建Controller

MS.WebApi應用程序中,Controllers文件夾下新建RoleController.cs:

using Microsoft.AspNetCore.Mvc;
using MS.Models.ViewModel;
using MS.WebCore.Core;
using System.Threading.Tasks;

namespace MS.WebApi.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class RoleController : ControllerBase
    {
        [HttpPost]
        public async Task<ExecuteResult> Post(RoleViewModel viewModel)
        {
            return new ExecuteResult();
        }
    }
}

刪除WeatherForecastController.csWeatherForecast.cs兩個類

完成后,啟動項目,打開Postman
按之前的方法,在MSDemo集合中添加一個新的POST請求Role,URL為http://localhost:5000/role
切換到Body選項卡,選擇raw,切換為json格式數據:

{
    "Name": "",
    "DisplayName": ""
}

點擊發送,可以看到提示字段必填了

輸入正確后,能返回true

Name輸入超過16個字符錯誤,驗證正則表達式等不再演示

以上便是ViewModel注解驗證的使用

項目完成后,如下圖所示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM