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.Jwt
、MS.DbContexts
兩個項目
添加業務操作枚舉和返回值定義
在MS.WebCore
類庫中新建Core文件夾,在該文件夾中新建ExecuteResult.cs
、ExecuteType.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.cs
和WeatherForecast.cs
兩個類
完成后,啟動項目,打開Postman
按之前的方法,在MSDemo集合中添加一個新的POST請求Role,URL為http://localhost:5000/role
切換到Body選項卡,選擇raw,切換為json格式數據:
{
"Name": "",
"DisplayName": ""
}
點擊發送,可以看到提示字段必填了
輸入正確后,能返回true
Name輸入超過16個字符錯誤,驗證正則表達式等不再演示
以上便是ViewModel注解驗證的使用
項目完成后,如下圖所示