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

  1. namespace MS.WebCore.Core
  2. {
  3. /// <summary>
  4. /// 执行返回结果
  5. /// </summary>
  6. public class ExecuteResult
  7. {
  8. public virtual ExecuteResult Set(bool isSucceed, string message)
  9. {
  10. IsSucceed = isSucceed;
  11. Message = message;
  12. return this;
  13. }
  14. /// <summary>
  15. /// 设定错误信息
  16. /// </summary>
  17. /// <param name="message"></param>
  18. /// <returns></returns>
  19. public virtual ExecuteResult SetFailMessage(string message)
  20. {
  21. return Set(false, message);
  22. }
  23. public virtual ExecuteResult SetFail()
  24. {
  25. return Set(false, string.Empty);
  26. }
  27. public ExecuteResult(bool isSucceed, string message)
  28. {
  29. Set(isSucceed, message);
  30. }
  31. /// <summary>
  32. /// 如果是给字符串,表示有错误信息,默认IsSucceed=false
  33. /// </summary>
  34. /// <param name="message"></param>
  35. public ExecuteResult(string message)
  36. {
  37. Set(false, message);
  38. }
  39. /// <summary>
  40. /// 如果是空的,没有信息,默认IsSucceed=true
  41. /// </summary>
  42. public ExecuteResult()
  43. {
  44. }
  45. /// <summary>
  46. /// 执行是否成功
  47. /// 默认为True
  48. /// </summary>
  49. public bool IsSucceed { get; set; } = true;
  50. /// <summary>
  51. /// 执行信息(一般是错误信息)
  52. /// 默认置空
  53. /// </summary>
  54. public string Message { get; set; } = string.Empty;
  55. }
  56. /// <summary>
  57. /// 执行返回结果
  58. /// </summary>
  59. /// <typeparam name="T"></typeparam>
  60. public class ExecuteResult<T> : ExecuteResult
  61. {
  62. public ExecuteResult<T> Set(bool isSucceed, string message, T result)
  63. {
  64. IsSucceed = isSucceed;
  65. Message = message;
  66. Result = result;
  67. return this;
  68. }
  69. public ExecuteResult<T> SetData(T data)
  70. {
  71. return Set(true, string.Empty, data);
  72. }
  73. public new ExecuteResult<T> SetFail()
  74. {
  75. return Set(false, string.Empty, default);
  76. }
  77. /// <summary>
  78. /// 设定错误信息
  79. /// 如果T正好也是string类型,可能set方法会存在用错的时候,所以取名SetMessage更明确
  80. /// </summary>
  81. /// <param name="message"></param>
  82. /// <returns></returns>
  83. public new ExecuteResult<T> SetFailMessage(string message)
  84. {
  85. return Set(false, message, default);
  86. }
  87. public ExecuteResult()
  88. {
  89. }
  90. public ExecuteResult(string message)
  91. {
  92. Set(false, message);
  93. }
  94. public ExecuteResult(bool isSucceed, string message)
  95. {
  96. Set(isSucceed, message);
  97. }
  98. public ExecuteResult(T result)
  99. {
  100. SetData(result);
  101. }
  102. public T Result { get; set; }
  103. }
  104. }

这个类是定义了业务相关方法调用的返回值结果,包含了是否成功、错误信息,也可以拓展泛型夹带其他内容

ExecuteType.cs

  1. namespace MS.WebCore.Core
  2. {
  3. /// <summary>
  4. /// 表示操作数据库类型
  5. /// </summary>
  6. public enum ExecuteType
  7. {
  8. /// <summary>
  9. /// 读取资源
  10. /// </summary>
  11. Retrieve,
  12. /// <summary>
  13. /// 创建资源
  14. /// </summary>
  15. Create,
  16. /// <summary>
  17. /// 更新资源
  18. /// </summary>
  19. Update,
  20. /// <summary>
  21. /// 删除资源
  22. /// </summary>
  23. Delete
  24. }
  25. }

这个枚举定义了业务操作的类型,对应数据库的CRUD

新建ViewModel

MS.Models类库中新建ViewModel文件夹,在该文件夹中新建RoleViewModel.cs类:

  1. using MS.DbContexts;
  2. using MS.Entities;
  3. using MS.UnitOfWork;
  4. using MS.WebCore.Core;
  5. using System.ComponentModel.DataAnnotations;
  6. namespace MS.Models.ViewModel
  7. {
  8. public class RoleViewModel
  9. {
  10. public long Id { get; set; }
  11. [Display(Name = "角色名称")]
  12. [Required(ErrorMessage = "{0}必填")]
  13. [StringLength(16, ErrorMessage = "不能超过{0}个字符")]
  14. [RegularExpression(@"^[a-zA-Z0-9_]{4,16}$", ErrorMessage = "只能包含字符、数字和下划线")]
  15. public string Name { get; set; }
  16. [Display(Name = "角色显示名")]
  17. [Required(ErrorMessage = "{0}必填")]
  18. [StringLength(50, ErrorMessage = "不能超过{0}个字符")]
  19. public string DisplayName { get; set; }
  20. [Display(Name = "备注")]
  21. [StringLength(4000, ErrorMessage = "不能超过{0}个字符")]
  22. public string Remark { get; set; }
  23. public ExecuteResult CheckField(ExecuteType executeType, IUnitOfWork<MSDbContext> unitOfWork)
  24. {
  25. ExecuteResult result = new ExecuteResult();
  26. var repo = unitOfWork.GetRepository<Role>();
  27. //如果不是新增角色,操作之前都要先检查角色是否存在
  28. if (executeType != ExecuteType.Create && !repo.Exists(a => a.Id == Id))
  29. {
  30. return result.SetFailMessage("角色不存在");
  31. }
  32. //针对不同的操作,检查逻辑不同
  33. switch (executeType)
  34. {
  35. case ExecuteType.Delete:
  36. //删除角色前检查角色下还没有员工
  37. if (unitOfWork.GetRepository<User>().Exists(a => a.RoleId == Id))
  38. {
  39. return result.SetFailMessage("还有员工正在使用该角色,无法删除");
  40. }
  41. break;
  42. case ExecuteType.Update:
  43. //如果存在Id不同,角色名相同的实体,则返回报错
  44. if (repo.Exists(a => a.Name == Name && a.Id != Id))
  45. {
  46. return result.SetFailMessage($"已存在相同的角色名称:{Name}");
  47. }
  48. break;
  49. case ExecuteType.Create:
  50. default:
  51. //如果存在相同的角色名,则返回报错
  52. if (repo.Exists(a => a.Name == Name))
  53. {
  54. return result.SetFailMessage($"已存在相同的角色名称:{Name}");
  55. }
  56. break;
  57. }
  58. return result;//没有错误,默认返回成功
  59. }
  60. }
  61. }

说明

  • Display是该字段的显示名称
  • Required注解标记该字段必填,不可为空
  • StringLength注解标记该字段长度
  • RegularExpression注解是正则表达式验证
  • 还有个Range注解特性是验证值的范围的,这里没用到

除了注解,我把对象字段的逻辑验证写在了ViewModel中,没有把它放在业务层是因为,我认为对象字段本身的合法性和对象是强相关的,就和注解直接写在ViewModel中而不是Service中一样,所以把字段的验证也写在了ViewModel里

对象字段的逻辑验证我区分了操作类型,新增时检查角色名是否有重复;删除时检查是否还有用户使用该角色;更新时检查用户提交的角色是否存在于数据库中

新建Controller

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

  1. using Microsoft.AspNetCore.Mvc;
  2. using MS.Models.ViewModel;
  3. using MS.WebCore.Core;
  4. using System.Threading.Tasks;
  5. namespace MS.WebApi.Controllers
  6. {
  7. [Route("[controller]")]
  8. [ApiController]
  9. public class RoleController : ControllerBase
  10. {
  11. [HttpPost]
  12. public async Task<ExecuteResult> Post(RoleViewModel viewModel)
  13. {
  14. return new ExecuteResult();
  15. }
  16. }
  17. }

删除WeatherForecastController.csWeatherForecast.cs两个类

完成后,启动项目,打开Postman

按之前的方法,在MSDemo集合中添加一个新的POST请求Role,URL为http://localhost:5000/role

切换到Body选项卡,选择raw,切换为json格式数据:

  1. {
  2. "Name": "",
  3. "DisplayName": ""
  4. }

点击发送,可以看到提示字段必填了

输入正确后,能返回true

Name输入超过16个字符错误,验证正则表达式等不再演示

以上便是ViewModel注解验证的使用

项目完成后,如下图所示

ASP.NET Core搭建多层网站架构【8.1-使用ViewModel注解验证】的更多相关文章

  1. ASP.NET Core搭建多层网站架构【0-前言】

    2020/01/26, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构 目录 0-前言 1-项目结构分层建立 2-公共基 ...

  2. ASP.NET Core搭建多层网站架构【1-项目结构分层建立】

    2020/01/26, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[1-项目结构分层建立] 文章目录 此分支项目代码 ...

  3. ASP.NET Core搭建多层网站架构【2-公共基础库】

    2020/01/28, ASP.NET Core 3.1, VS2019,Newtonsoft.Json 12.0.3, Microsoft.AspNetCore.Cryptography.KeyDe ...

  4. ASP.NET Core搭建多层网站架构【3-xUnit单元测试之简单方法测试】

    2020/01/28, ASP.NET Core 3.1, VS2019, xUnit 2.4.0 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[3-xUnit单元测试 ...

  5. ASP.NET Core搭建多层网站架构【4-工作单元和仓储设计】

    2020/01/28, ASP.NET Core 3.1, VS2019, Microsoft.EntityFrameworkCore.Relational 3.1.1 摘要:基于ASP.NET Co ...

  6. ASP.NET Core搭建多层网站架构【5-网站数据库实体设计及映射配置】

    2020/01/29, ASP.NET Core 3.1, VS2019, EntityFrameworkCore 3.1.1, Microsoft.Extensions.Logging.Consol ...

  7. ASP.NET Core搭建多层网站架构【6-注册跨域、网站核心配置】

    2020/01/29, ASP.NET Core 3.1, VS2019, NLog.Web.AspNetCore 4.9.0 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站 ...

  8. ASP.NET Core搭建多层网站架构【7-使用NLog日志记录器】

    2020/01/29, ASP.NET Core 3.1, VS2019, NLog.Web.AspNetCore 4.9.0 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站 ...

  9. ASP.NET Core搭建多层网站架构【8.2-使用AutoMapper映射实体对象】

    2020/01/29, ASP.NET Core 3.1, VS2019, AutoMapper.Extensions.Microsoft.DependencyInjection 7.0.0 摘要:基 ...

随机推荐

  1. scw——01 java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMake

    错误: java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.Mock ...

  2. util之ArrayList

    Java之ArrayList 方法: add(o: E): void 在list的末尾添加一个元素o add(index: int, o: E): void 在指定的index处插入元素o clear ...

  3. 不能暴露服务给外部环境,因为nginx-ingress-control启动失败

    不能暴露服务给外部环境,因为nginx-ingress-control启动失败 待办 rancher 和k8s中的端口冲突,nginx-ingress-control都需要使用80端口 以及443端口 ...

  4. SpringMVC项目使用elastic search搜索

    项目需要,引入了elastic search(后续简称es),后面将介绍本地对es的安装,使用以及java连接es查询的整个过程. 1.es索引字段建立与修改,以curl新增一个索引字段示例 curl ...

  5. 【C语言】移动指针

    移动指针 #include<stdio.h> int main() { char *s="哈哈哈哈哈哈"; for(*s;s!="\0";s++) ...

  6. Nginx可以做什么

    Nginx能做什么 ——反向代理 ——负载均衡 ——HTTP服务器(动静分离) ——正向代理 反向代理 反向代理应该是Nginx做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向代理(R ...

  7. DFT 问答 II

    1. Boundary Scan A:Boundary scan 顾名思义,是附加在芯片I/O 周边的扫描测试链,它通过专门的测试端口(TAP)访问.在测试模式下,边界扫描链会接管功能逻辑,对I/O进 ...

  8. python 序列 倒着取元素

    当要倒着取元素时,用s[-2]只能取一个, 如果取多个时用s[-9:-1],注意,最后一个-1是不取出来的. 此时要用s[-9:] 最后一个空着就可以取出来了.

  9. linux 下查看Tomcat的状态,以及开启停止服务命令

    1.首先进入你的tomcat 的bin目录下 cd /你的安装目录/tomcat/bin 查看服务启动情况 ps -ef|grep java 此条命令具体含义 ps:将某个进程显示出来 -A 显示所有 ...

  10. 剑指offer 面试题36.二叉搜索树与双向链表

    中序递归,一个pre节点记录前一个节点 /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; Tre ...