ASP.NET Core MVC中的 [Required]与[BindRequired]

在开发ASP.NET Core MVC应用程序时,需要对控制器中的模型校验数据有效性,元数据注释(Data Annotations)是一个完美的解决方案。

元数据注释最典型例子是确保API的调用者提供了某个属性的值,在传统的ASP.NET MVC中使用的是RequiredAttribute特性类。该属性仍然可以在ASP.NET Core MVC中使用,但也提供了一个新的特性类BindRequiredAttribute

今天让我们来看看它们之间的细微差别。

RequiredAttribute的典型用法

想象一下,您的模型是下面的BookOrder类。为了强制AuthorTitle属性的值始终出现在传入的请求中,并且值不能为空,我们使用RequiredAttribute修饰它们。

    public class BookOrder{[Required]        
   public string Author { get; set; }[Required]        
   public string Title { get; set; }}

这在传统的ASP.NET MVC中是很常见方法。有了这个,您可以验证ModelState是否存在错误,因为对这些属性的验证失败会反映在这里。示例:

    [Route("bookorder")]    
   public IActionResult PostBook([FromForm]BookOrder bookOrder)    {      
    if (!ModelState.IsValid){          
     return BadRequest(ModelState);}     // 正常逻辑代码return Content("OK");}

如果传入的请求中缺少两个必需的属性(或者属性的值为String.Empty),则响应将是一个400状态码,并将模型状态错误序列化到响应中。

使用Postman进行测试,请求中只提供了Title属性的值,而未提供Author属性的值:

常有趣的问题,例如当我们添加类似数量的属性时(类型为int)。在这种情况下,RequiredAttribute将无法正常工作,因为默认值为0,并且该属性不可能为空。即使客户端在不包括属性值的情况下提交请求,模型实例的值都将为0。换句话说,RequiredAttribute不起作用。在我们的例子中,我们使用的是int,但是同样适用于所有值的类型,例如DateTimeGuid

以前,在传统的ASP.NET MVC中,解决这个问题的方法是使用一个可为空类型,如下所示:

    public class BookOrder{[Required]       
        public string Author { get; set; }[Required]      
       public string Title { get; set; }[Required]      
      public int? Quantity { get; set; }}

虽然它解决了这个问题,但是这不是最优雅的方式。Quantity属性不能为null,如果API的调用者未提供该属性的值,则该值保持为null,配合RequiredAttribute特性可以达到我们的目的。

这种方法的缺点是,在正常逻辑代码中,您需要直接访问可为空的Value属性。

    [Route("bookorder")]    
   public IActionResult PostBook([FromForm]BookOrder bookOrder)    {      
    if (!ModelState.IsValid){          
     return BadRequest(ModelState);}     // 正常逻辑代码var requestedQuantity = bookOrder.Quantity.Value;        return Content("OK");}

如果通过静态分析工具来检查代码,因为它们找不不到空值检测,所以会警告您可能出现空引用异常(即使在逻辑上,ModelState检测是足够的)。所以这并不是令人赏心悦目的方案。

如果在VS中安装了Resharper工具,会显示如下警告:

这就是BindRequiredAttribute产生的原因。它和RequiredAttribute的工作方式类似,它要求请求必须提示属性的值 。

我们将模型改为如下结构,Quantity属性为int类型,并使用[BindRequired]修饰:

    public class BookOrder{[Required]        
         public string Author { get; set; }[Required]      
        public string Title { get; set; }[BindRequired]      
       public int Quantity { get; set; }}

使用Postman进行测试,在请求体不包括Quantity属性的值:

测试结果为ModelState.IsValid返回的false,要求提供Quantity属性的值。

RequiredAttribute与BindRequiredAttribute的差别

BindRequiredAttribute特性类只要求API的调用者提供该属性的值,但不进行空值检测,允许提供的值为空,例如我们将模型改为如下示例,所有属性中都使用了BindRequiredAttribute特性类进行注释:

    public class BookOrder{[BindRequired]        
          public string Author { get; set; }[BindRequired]        
          public string Title { get; set; }[BindRequired]        
          public int Quantity { get; set; }}

使用Postman进行测试,在请求体包括这三个属性名称的参数,但是属性的值均为空或默认值:

测试结果为正常,BindRequiredAttribute特性类只要求API的调用者提供该属性的值,但不进行空值检测,允许提供的值为空

RequiredAttribute 与 BindRequiredAttribute 混用问题

当然,在代码中混合使用[Required][BindRequired]并不是一个最令人满意的效果。值得庆幸的是,ASP.NET Core MVC为您提供了足够的灵活性来改变RequiredAttribute的行为,强制它包含BindRequiredAttribute的行为。

您可以通过实现自己的IBindingMetadataProvider并在您的应用程序全局范围内注册来实现这一目标。

    public class RequiredBindingMetadataProvider : IBindingMetadataProvider{     
      public void CreateBindingMetadata(BindingMetadataProviderContext context)  {          
       if (context.PropertyAttributes?.OfType<RequiredAttribute>().Any() ?? false) {context.BindingMetadata.IsBindingRequired = true;}}}

在全局范围内注册它:

    public void ConfigureServices(IServiceCollection services)    {services.AddMvc(o =>{o.ModelMetadataDetailsProviders.Add(new RequiredBindingMetadataProvider());});}

相关补充内容

1、ASP.NET Core MVC还提供了BindNeverAttribute特性类用于指定该属性不进行模型绑定。例如:您拥有一个像IsAdmin这样的属性,这需要通过服务端来指定,而不是通过客户提交的数据来指定;
2、如果客户端提交的是Json格式的数据,BindRequiredAttributeBindNeverAttribute特性类就不会起任何作用,这是因为模型直接通过Json.Net反序列化来创建,MVC框架并不知道属性的值从何而来。

上面补充的两点,感兴趣的同学可以自己进行测试。

总结

  • RequiredAttribute特性类的行为在传统的ASP.NET MVC与ASP.NET Core MVC是一致的,校验属性的值不能为null

  • RequiredAttribute特性类对于值类型的属性,就没有任何效果了,所以在编码的过程将属性的类型改为可为空类型,不过编码的过程就比较纠结了,需要访问可为空类型的Value属性,而且静态代码检测工具会警告需要进行非空的校验;

  • BindRequiredAttribute特性类可以解决值类型默认值的问题,强制要求客户端提交请求时,必须包含属性的值,不过属性的值可以为空,不进行非空的校验;

  • RequiredAttributeBindRequiredAttribute混合使用的情况下,我们也提供了优雅的方法,让RequiredAttribute包含BindRequiredAttribute的行为。


原文地址: https://www.cnblogs.com/tdfblog/p/required-and-bindrequired-in-asp-net-core-mvc.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322402.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES集群管理

转载自 ES集群管理 8 集群管理 ES通常以集群方式工作&#xff0c;这样做不仅能够提高 ES的搜索能力还可以处理大数据搜索的能力&#xff0c;同时也增加了系统的容错能力及高可用&#xff0c;ES可以实现PB级数据的搜索。 下图是ES集群结构的示意图&#xff1a; 从上图总结以下…

【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. Java的注释方式二. 标识符三. 关键字四. 全篇总结 &#x1f4d1;前言 在Java编程…

P5290-[十二省联考2019]春节十二响【贪心,堆】

正题 题目链接:https://www.luogu.org/problemnew/show/P5290 题目大意 将一棵树的所有节点分城若干个组。每个组的价格是这个组中价格最大的点&#xff0c;要求这个组中没有任何祖孙关系。 求所有组的权值和最小。(1号为根节点) 解题思路 我们先想10,11,1210,11,1210,11,12…

07-MyBatis 核心配置文件

MyBatis 核心配置文件 目录 properties 定义属性及读取属性文件settings 设置运行时行为typeAliases 类型别名定义单个别名批量定义别名typeHandlers 类型处理器Plugins&#xff08;后续有文章专门介绍这个&#xff09;Environments 运行环境databaseIDProvider 定义数据库厂…

Office 365也是.NET Core应用开发新战场

最近有幸阅读了陈希章花了一年时间为国内开发者贡献的《Office 365 开发入门指南》。 虽然早期接触过SharePoint的开发&#xff0c;2007年之后就再也没有接触SharePoint的开发&#xff0c;这次阅读这本书让我重新认识了Office的系统开发技术&#xff0c;让我意识到现在的Office…

jzoj4802-[GDOI2017模拟9.24]探险计划【费用流,拆点】

正题 题目大意 一个nnn行的不完全矩阵第iii行有mi−1mi-1mi−1个格子&#xff0c;然后每个格子有危险度。 每次可以从(i,j)(i,j)(i,j)走到(i−1,j)(i-1,j)(i−1,j)或(i−1,j−1)(i-1,j-1)(i−1,j−1) 求 m次&#xff0c;每个格子和路不可以重复走的最小危险度。m次&#xff0…

Scala与Java差异(一)之基础语法

一、Scala解释器的使用 &#xff08;1&#xff09;REPL Read&#xff08;取值&#xff09;-> Evaluation&#xff08;求值&#xff09;-> Print&#xff08;打印&#xff09;-> Loop&#xff08;循环&#xff09;。 scala解释器也被称为REPL&#xff0c;会快速编译…

08-输出类型

输出类型 目录 输出简单类型输出 Map 类型key:列名 value:列名对应的值key:自己指定的列 value:自定义对象resultMap输出简单类型 CustomerMapper.java&#xff1a;返回值为简单类型。 public interface CustomerMapper {/*查询总数*/public Integer getAccountCustomer();…

在Ubuntu 16.04环境下安装Docker-CE(附视频教程)

“ 任何的课程都逃不开理论的支持”久等了各位&#xff0c;上一篇说Docker开始的消息已经过去了一周多的时间&#xff0c;今天推送的消息是告诉大家视频可以学习了&#xff01;52ABP .NET CORE QQ群 : 633751348大纲Docker的介绍Ubuntu下安装Docker快速体验Docker利用Docker搭…

jzoj4800-[GDOI2017模拟9.24]周末晚会【dp,循环重构】

正题 题目大意 nnn个人的圆桌&#xff0c;可以放男可以放女&#xff0c;然后要求不能有连续kkk个女生坐在一起。求方案总数。 解题思路 先不考虑圆桌&#xff0c;设fi,jf_{i,j}fi,j​表示放了i个人&#xff0c;最前面有连续jjj个女生&#xff0c;动态转移方程显然 fi,jfi−1,j…

Scala与Java差异(二)之条件控制与循环

一、if表达式 &#xff08;1&#xff09;if表达式的定义 在Scala中&#xff0c;if表达式是有值的&#xff0c;就是if或者else中最后一行语句返回的值。 例如&#xff0c;val age 30; if (age > 18) 1 else 0 可以将if表达式赋予一个变量&#xff0c;例如&#xff0c;va…

WebApi client 的面向切面编程

.Net的面向切面编程.Net的服务端应用AOP很常见&#xff0c;在Asp.net MVC与Asp.net WebApi等新框架里到处都有AOP的影子&#xff0c;我们可以把一个服务方法“切”为很多面&#xff0c;日志面、验证面、请求方式处理、接口业务实现等多个面&#xff0c;有一些面可以使用过滤器特…

09-一对多关系建表

多表操作 目录 表之间关系一对多关系建表原则表之间关系 一对一关系&#xff1a;一夫一妻。 一对多关系&#xff1a; 一个部门有多个员工&#xff0c;一个员工只能属于某一个部门。 一个班级有多个学生&#xff0c;一个学生只能属于一个班级。 多对多关系&#xff1a; 一个…

jzoj6191-[NOI2019模拟2019.5.31]Exchange【线段树】

正题 题目大意 一个序列&#xff0c;给定若干个区间[l..r][l..r][l..r] 从l∼rl\sim rl∼r任意一个位置出发&#xff0c;见到比手中大的数字就交换&#xff0c;到rrr求最小的交换次数 (注意&#xff0c;并不是真的交换) 解题思路 首先算出每个点的后继(在它后面第一个比他大的…

面试阿里挂了却拿到网易、点我达offer,一个三年经验Java程序员的面试总结

转载自 面试阿里挂了却拿到网易、点我达offer&#xff0c;一个三年经验Java程序员的面试总结 前言 15年毕业到现在有三年多了&#xff0c;最近去面试了阿里集团&#xff08;菜鸟网络&#xff0c;蚂蚁金服&#xff09;、网易、滴滴、点我达&#xff0c;最终收到点我达、网易o…

10-多对一左连接查询分步查询(查询所有订单及订单对应的客户)

左连接查询&#xff08;级联查询&#xff09; 回顾一下&#xff1a;左连接查询&#xff0c;将左边表(order)里的全部内容查出&#xff0c;右边表(customer)查满足条件的。 SELECT * FROM order AS o LEFT JOIN customer AS c on o.cust_id c.cust_id;1那么在 MyBatis 中如何…

入门干货之Grpc的.Net 封装-MagicOnion

0x01、Grpc1、介绍Google主导开发的RPC框架&#xff0c;使用HTTP/2协议并用ProtoBuf作为序列化工具&#xff0c;支持多种语言。在.NET Core “大更新” 之前&#xff0c;也就是目前来说还算是个很不错的选择。2、吐槽a、有很多性能比较的文章拿Grpc开涮.b、搭建困难&#xff0c…

欢乐纪中A组周六赛【2019.6.1】

前言 六一儿童节快乐(然而我还在学校) dalao都走了&#xff0c;导致只剩下我们这帮菜鸡在被虐 成绩 JJJ表示初中&#xff0c;HHH表示高中后面加的是几年级 RankRankRankPersonPersonPersonScoreScoreScoreAAABBBCCC111(J−2)ZYC(J-2)ZYC(J−2)ZYC1301301303030301001001000002…

11-分步查询懒加载

分步查询——懒加载模式 目录 懒加载模式示例不使用懒加载使用懒加载aggressiveLazyLoadinglazyLoadTriggerMethods所谓懒加载&#xff0c;也称延时加载&#xff0c;是指不一下子加载完全部资源。需要用到哪些资源才去加载这些资源&#xff0c;用不到的资源&#xff0c;就不去…

利用Service Fabric承载eShop On Containers

从模块化到微服务化从Pet Shop 到eShop on Container都是Microsoft在技术演进的路径上给开发者展示.Net的开发能力和架构能力的Sample工程&#xff0c;Petshop的时候更多的是展现应用的分层架构&#xff0c;设计的抽象与模块间的通讯。到了eShop on Container更多的关注在架构设…