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.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注解验证的使用
项目完成后,如下图所示



ASP.NET Core搭建多层网站架构【8.1-使用ViewModel注解验证】的更多相关文章
- ASP.NET Core搭建多层网站架构【0-前言】
2020/01/26, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构 目录 0-前言 1-项目结构分层建立 2-公共基 ...
- ASP.NET Core搭建多层网站架构【1-项目结构分层建立】
2020/01/26, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[1-项目结构分层建立] 文章目录 此分支项目代码 ...
- ASP.NET Core搭建多层网站架构【2-公共基础库】
2020/01/28, ASP.NET Core 3.1, VS2019,Newtonsoft.Json 12.0.3, Microsoft.AspNetCore.Cryptography.KeyDe ...
- 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单元测试 ...
- ASP.NET Core搭建多层网站架构【4-工作单元和仓储设计】
2020/01/28, ASP.NET Core 3.1, VS2019, Microsoft.EntityFrameworkCore.Relational 3.1.1 摘要:基于ASP.NET Co ...
- ASP.NET Core搭建多层网站架构【5-网站数据库实体设计及映射配置】
2020/01/29, ASP.NET Core 3.1, VS2019, EntityFrameworkCore 3.1.1, Microsoft.Extensions.Logging.Consol ...
- 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搭建后端多层网站 ...
- 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搭建后端多层网站 ...
- ASP.NET Core搭建多层网站架构【8.2-使用AutoMapper映射实体对象】
2020/01/29, ASP.NET Core 3.1, VS2019, AutoMapper.Extensions.Microsoft.DependencyInjection 7.0.0 摘要:基 ...
随机推荐
- SuperSocket与SuperSocket.ClientEngine实现Protobuf协议
参考资料说明 SuperSocket文档 http://docs.supersocket.net/ Protobuf语言参考 https://developers.google.com/protoco ...
- MySQL转译
/* 案例3:查询员工名中第二个字符为 _ 的员工名 */ SELECT last_name, salary FROM employees WHERE last_name LIKE '_$_%' ES ...
- spring_boot 加入 mybatis
第一步: <!-- mybatis启动器 自动包含jdbc所以不需要再次引入jdbc依赖 --> <dependency> <groupId>org.mybatis ...
- Virtual Judge POJ 1002 487-3279
模拟 #include<iostream> #include<algorithm> #include<string.h> #include<stdio.h&g ...
- mini-batch是什么 以及dataloader的作用
mini-batch是什么 以及dataloader的作用 待办 我们在训练神经网络时,使用的是mini-batch(一次输入多张图片),所以我们在使用一个叫DataLoader的工具为我们将5000 ...
- Flink架构(三)- 事件-时间(Event-Time)处理
3. 事件-时间(Event-Time)处理 在“时间语义”中,我们强调了在流处理应用中时间语义的重要性,并解释了处理时间与事件时间的不同点.处理时间较好理解,因为它基于本地机器的时间,它产生的是有点 ...
- 使用ResponseBodyAdvice统一包装响应返回String的时候出现java.lang.ClassCastException: com.xxx.dto.common.ResponseResult cannot be cast to java.lang.String
代码如下: @Override public ResponseResult<Object> beforeBodyWrite(Object returnValue, MethodParame ...
- 8.10-Day2T3 镇守府
emm IOI原题(洛谷,bzoj都有) 其实并没有怎么搞懂dp方程转移那部分 就...粘个(抄来的)代码过来吧 #include<bits/stdc++.h> using namespa ...
- 利用Xshell5从本机上向Linux(虚拟机中)上传文件
Xmanager Enterprise 5云盘分享: http://pan.baidu.com/s/1jIkiQNW 1. 用ifconfig命令查看Linux的IP地址 2. 由于没有IP,所以我 ...
- redis哈希操作
用户可以通过执行hset命令为哈希中的指定字段设置值: 127.0.0.1:6379> hset hash field value 根据给定的字段是否存在于散列中,hset命令的行为也会有所不同 ...