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注解验证的使用

项目完成后,如下图所示

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. JavaScript 开胃菜

    注释 单行注释:// 快捷键: CTRL + / 多行注释: /* 内容 */ 快捷键: ctrl + shift + / 变量 申明变量 var name; 赋值 name = 'peach'; 初 ...

  2. sql server和eclipse连接问题

    最近学习java,需要用的数据库sql sever,这就有一个连接问题需要设置 首先需要下载sql server,可查看我的博客sql sever下载教程: 连接教程:eclipse连接sql ser ...

  3. input输入框在ios手机上获取焦点后有一个灰色阴影

    遇到的场景: 有一个输入框 设置 outline:none 然后我又想给他设置获取焦点的颜色 然后 我给input 设置 border 为 1px t透明的 然后 获取焦点的时候 重新设置border ...

  4. 「题解」「CF1103B」Game with modulo

    简易中文题目 猜一个数字 \(a\),而你可以向机器提问一对 \((x,y)\) ,如果 \(x\bmod a\ge y \bmod a\) 机器返回字符串 x,反之返回字符串 y . 询问不能超过 ...

  5. apache http server 和tomcat的区别 以及nginx

    Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器. 要明白他们之间的区别,我们首先需要明白HTTP协议.HTML页面.JSP.Servlet之 ...

  6. 算法_hdoj_1003

    question: Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  7. 2019年牛客多校第一场B题Integration 数学

    2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...

  8. 浅谈DAO工厂设计模式(工厂模式的好处)

    随着软件分层设计的流行及广泛的应用,对于DAO的设计模式大家已经不再陌生了,DAO层已经在软件系统的开发中成为必不可少的一层,将后台的数据层和前台的VO进行分离.前段时间也针对于DAO的设计介绍过一个 ...

  9. LEETCODE80. 删除排序数组中的重复项

    俺的: class Solution: def removeDuplicates(self, nums: List[int]) -> int: if(len(nums)==0): return ...

  10. js Array 的所有方法

    下面的这些方法会改变调用它们的对象自身的值: Array.prototype.copyWithin()  在数组内部,将一段元素序列拷贝到另一段元素序列上,覆盖原有的值. Array.prototyp ...