一个asp.net core项目,一定包含了各种的实体,在RESTful api里面,有很多的参数传递,不建立实体则大量的参数需要自定验证正确性,并且Action上面会写的密密麻麻的参数

在asp.net 2.0的时候,就推出了ModelState,顾名思义,这个是模型状态,用于验证实体对象的

如何模型验证

用法是在需要验证的地方打上继承了ValidationAttribute的特性,比如常见的RequiredAttribute,这个是验证对象是否存在

    /// <summary>
/// Admin Request Model
/// </summary>
public class AdminRequestModel
{
/// <summary>
/// User
/// </summary>
[Required]
public string User { get; set; } /// <summary>
/// Account
/// </summary>
[Required]
public string Account { get; set; }
}

这是一个实体

我们要验证的Model里是“User”属性和“Account”属性不能为空

写在Action上面

        /// <summary>
/// Test Admin
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("Admin")]
public ResponseModel Admin(AdminRequestModel model)
{
return new AdminResponseModel()
{
User = model.User
};
}

在asp.net core 2.1之前版本的web api则改为

        /// <summary>
/// Test Admin
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("Admin")]
public ResponseModel Admin([FromForm] AdminRequestModel model)
{
return new AdminResponseModel()
{
User = model.User
};
}

进入了Action的就是通过了基础模型验证的实体对象,数据库操作之类的业务验证,就在Action里面处理

怎么启用模型验证

全局过滤器

    /// <summary>
/// Gold Filter Validate Model
/// </summary>
public class GoldModelFilter : IActionFilter
{
/// <summary>
/// Action Before
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
} /// <summary>
/// Action After
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
throw new ValidateException(
context.ModelState.Values
.FirstOrDefault(item => item.Errors.Count >
)
.Errors.FirstOrDefault().ErrorMessage
);
}
}

然后在

Startup.cs的ConfigureService内写的AddMvc改为

            services.AddMvc(options=> {
options.Filters.Add<GoldModelFilter>();
}));

我们不需要全局验证的则这样写

    public class ModelFilterAttribute:ActionFilterAttribute
{
/// <summary>
/// Action Before
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
//leave out
} /// <summary>
/// Action After
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
//leave out
}
}

是不是很像,是的,就是一样的,只是一个是特性,一个是过滤器,内部的流程也差不多

ActionFilterAttribute还有很多东西,就暂不赘述了

我们在需要模型验证的Action上面打上特性就可以了

如何扩展自定义模型验证

CustomValidationAttribute,顾名思义这个是做自定义模型验证的,支持给属性、字段、方法、参数和实体对象验证的

他有两个参数,参数1是自定义的验证类Type,参数2是方法名

自定义验证类需要是公开类,自定义方法也是公开方法

方法参数1是object类型,参数2是ValidationContext类型

参数1是验证的内容,参数2是验证的上下文

包括

DisplayName 描述名

MemberName 成员名

ObjectInstance 整个验证的实体

ObjectType 整个验证的实体类型

还一个方法GetService

这个是获取服务的,依赖注入里面的服务,可以通过这个取出来

如果我们要对之前的AdminRequestModel这个实体验证User是否等于Account,不等于,则写一条错误日志,然后验证失败

    /// <summary>
/// Admin Validate
/// </summary>
public class AdminValidate
{
/// <summary>
/// Ordinary Validate
/// </summary>
/// <param name="value"></param>
/// <param name="validationContext"></param>
/// <returns></returns>
public static ValidationResult Ordinary(object value, ValidationContext validationContext)
{
if (value is AdminRequestModel model)
{
if (!model.User.Equals(model.Account))
{
var logger = validationContext.GetService(typeof(ILogger<AdminValidate>)) as ILogger<AdminValidate>; logger.LogError("User not equals Account"); return new ValidationResult("User not equals Account");
} return ValidationResult.Success;
} return new ValidationResult("Type Error");
}
}

AdminRequestModel上面加一行[CustomValidation(typeof(AdminValidate), "Ordinary")]

这种是低复用的场景下,给特定的做验证的,如果我们这种验证很多,而且很多处都有相似的验证,那么可以写一个特性,继承ValidationAttribute

这个的验证的有两种场景,单纯的内容验证,没有功能性的,比如上面这种,验证失败,悄悄写一条错误日志,甚至发一个预警邮件

那么重构两个方法FormatErrorMessage和IsValid,前者返回错误信息,后者是验证的

除了验证,还有一些功能性的

那么请重构IsValid方法

代码和AdminValidate.Ordinary雷同

扩展

如果我们的过滤特性里面也有一些功能性呢?

    /// <summary>
/// Register Service Action Filter
/// </summary>
public class ServiceActionFilterAttribute : ActionFilterAttribute
{
private ILogger<ServiceActionFilterAttribute> Logger { get; } /// <summary>
/// Generate
/// </summary>
/// <param name="logger"></param>
public ServiceActionFilterAttribute(ILogger<ServiceActionFilterAttribute> logger)
{
Logger = logger;
} /// <summary>
/// Action Before
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
//leave out
} /// <summary>
/// Action After
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
//leave out
}
}

这样是不能打在Action上面了

这个时候,我们就要掏出ServiceFilterArribute或者TypeFilterAttribute

        /// <summary>
/// Test Admin
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost("AdminDIFilterAttibute")]
[ServiceFilter(typeof(ServiceActionFilterAttribute))]
public ResponseModel AdminDIFilterAttibute(AdminRequestModel model)
{
return new AdminResponseModel()
{
User = model.User
};
}

前者是Type必须注册在依赖注入容器里面的,后者是不需要的

项目地址:

https://github.com/htrlq/AspNetCoreTemplate

从零写一个Asp.net core手脚架(模型验证)的更多相关文章

  1. 从零写一个Asp.net core手脚架 (异常处理)

    既然是手脚架,那么肯定得明白,手脚架是有限资源的一个整合,我们尽可能完善它,并保留可扩展性才是最终目的,尽可能减少硬编码,让业务不满足的情况下,可以自行修改 我们把解决方案取名Asp.netCoreT ...

  2. asp.net core 简化模型验证 modelState.IsValid不用每一个写

    第一种:直接在执行action之前验证模型 实现 IActionFilter public class ModelStateFilter : IActionFilter { public void O ...

  3. asp.net core自定义模型验证——前端验证

    转载请注明出处:http://www.cnblogs.com/zhiyong-ITNote/ 官方网站:https://docs.microsoft.com/zh-cn/aspnet/core/mvc ...

  4. Asp.Net Core 全局模型验证

    public class ActionFilter : IActionFilter { /// <summary> /// action 执行之前 /// </summary> ...

  5. 手把手教你从零写一个简单的 VUE--模板篇

    教程目录1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 Hello,我又回来了,上一次的文章教会了大家如何书写一个简单 VUE,里面实现了VUE 的数据驱动视图 ...

  6. Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群

    Kubernetes简介 Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的 ...

  7. 使用Visual Studio Code创建第一个ASP.NET Core应用程序

    全文翻译自:Your First ASP.NET Core Application on a Mac Using Visual Studio Code 这篇文章将向你展示如何在Mac上写出你的第一个A ...

  8. 如何一秒钟从头构建一个 ASP.NET Core 中间件

    前言 其实地上本没有路,走的人多了,也便成了路. -- 鲁迅 就像上面鲁迅说的那样,其实在我们开发中间件的过程中,微软并没有制定一些策略或者文档来约束你如何编写一个中间件程序, 但是其中却存在者一些最 ...

  9. 手把手教你从零写一个简单的 VUE

    本系列是一个教程,下面贴下目录~1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 今天给大家带来的是实现一个简单的类似 VUE 一样的前端框架,VUE 框架现在应 ...

随机推荐

  1. 不用破解版的 Navicat 了,几款免费且好用的 SQL 客户端送给你

    我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 没别的意思,今天就是为了给你推荐几款 MySQL 客户端,这几款 ...

  2. WPF DataGrid ScrollBar Style

    效果图如下 代码 <DataGrid.Resources> <Style TargetType="{x:Type ScrollBar}"> <Sett ...

  3. 源码剖析@ApiImplicitParam对@RequestParam的required属性的侵入性

    问题起源 使用SpringCloud构建项目时,使用Swagger生成相应的接口文档是推荐的选项,Swagger能够提供页面访问,直接在网页上调试后端系统的接口, 非常方便.最近却遇到了一个有点困惑的 ...

  4. Jmeter系列(43)- 详解 Jmeter 图形化 HTML 压测报告之 Charts 模块

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html Charts 介绍 包含了各种详细信息 ...

  5. shell专题(四):Shell中的变量

    4.1 系统变量 1. 常用系统变量 $HOME.$PWD.$SHELL.$USER等 2.案例实操 (1)查看系统变量的值 [atguigu@hadoop101 datas]$ echo $HOME ...

  6. 概率图模型(CPD)(二)

    CPD是conditional probability distribution的缩写,翻译成中文叫做 条件概率分布.在概率图中,条件概率分布是一个非常重要的概念.因为概率图研究的是随机变量之间的练习 ...

  7. 微信浏览器内 h5 直接唤醒 app 之 微信开放标签 wx-open-launch-app

    以前微信浏览器内想要直接唤醒 app 要么接微信的应用宝要么你是腾讯的干儿子. 而在微信在2020年5月分推出了“微信开放标签”功能 wx-open-launch-app 用于微信浏览器内直接唤醒 a ...

  8. 01-MySQL支持的数据类型

    1.数值类型 整数类型 MySQL 支持的整数类型有 SQL 标准中的整数类型 INTEGER,SMALLINT,TINYINT.MEDIUMINT和BIGINT.其整数类型的特性如下表所示: 在上述 ...

  9. [Antd-vue] Warning: You cannot set a form field before rendering a field associated with the value.

    在用ant-design-vue的框架中,使用到了这种场景,就是点击编辑按钮,弹出modal模态框,渲染modal模态框中的form表单页面,并给表单赋值,但是在给表单赋值的时候,总是会报错. 错误提 ...

  10. OSCP Learning Notes - Enumeration(3)

    SMB Enumeration 1. Set the smb configurations. locate smb.conf vim /etc/samba/smb.conf Insert the gl ...