前言

一年多没更新博客,上一次写此系列还是四年前,虽迟但到,没有承诺,主打随性,所以不存在断更,催更,哈哈,上一篇我们细究从请求到绑定详细原理,本篇则是探讨模型绑定细节,当一个问题产生到最终解决时,回过头我们整体分析其产生背景以及设计思路才能有所获。好了,废话不多说,我们开始模型绑定细节之旅。

问题产生

我们定义一个模型,然后进行查询请求,当然,此时我们在后台控制器Action方法上推荐明确使用查询特性即FromQuery接收,代码如下

public class UserAddress
{
public string Code { get; set; }
}
[ApiController]
[Route("api/[controller]/[action]")]
public class UserAddressController : ControllerBase
{
private readonly ILogger<UserAddressController> _logger; public UserAddressController(ILogger<UserAddressController> logger)
{
_logger = logger;
} [HttpGet]
public IActionResult Get([FromQuery] UserAddress address)
{
return Ok(address);
}
}

没任何毛病,接下来我们在定义用户地址类上增加一个属性,如下所示

public class UserAddress
{
public string Code { get; set; }
public string Address { get; set; }
}

值绑定不上,这是神马情况,这难道是官方的Bug吗,我们用6.0和7.0都是如此,毫无疑问,利用.NET 8.0依然是此等结果,问题来了,请稍加思考大概是什么原因,让我们继续往下分析

根因源码分析

通过前后对比我们可以初步分析到原因可能是二方面之一或者二者结合,其一,对象属性address和接收对象参数变量address不能相同(不区分大小写),其二,接受对象参数变量address和URL上的键名称address不能相同(不区分大小写)。我们暂且只能分析到这个地方,当然,我们一试便知,至于根因是什么,接下来我们只能去分析模型绑定源码,说到分析源码,可能有些童鞋不知从何开始,这里给出我们从0开始分析其根因的整个过程,以供需要的童鞋做参考哈。仅我个人看法,除非精通,否则必会经历一个过程,这是必然,所以不用怀疑任谁都不能立马找到大概源码在哪里,我们注意关注点分析,别看着看着跑偏了,既然是模型绑定而且是查询绑定,这是在了解基本原理或学习官网文档有所印象的前提下,先看这里

然后我们怎么开始呢,我们直接自定义实现一个查询字符串值绑定即将上述代码拷贝一份出来,比如有些是有依赖的等等,将其修改去掉等等处理,还是我们强调的关注点,最后我们还要添加自定义实现

   builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Insert(0, new QueryStringValueProviderFactory());
});

我们看到实际上值都已正确获取到,但实际上传过来的键应该是属性Code或者Address才对,同时我们发现在此实现中包含了一个是否包含前缀的方法,这好像貌似就是针对我们绑定的属性加上方法上的参数变量即address,所以我们断点一步步调试进入该方法具体实现

源码调试现在还是方便了很多,我们来到绑定源头即将ActionContext转换为ModelBindingContext,也就是调用具体绑定实现之前即相关参数绑定准备前夕,我们看到赋值给了模型绑定上下文中的模型名称即ModelName,我们猜测这就是增加的前缀,继续往下调试实际调用的绑定者是哪一个,我们看到实际使用的复杂对象绑定,框架内置实现了十几个绑定,ValueProvider只是其中后台接收最简单的参数类型或者直接接收请求上下文相关的预处理,大多都由ModelBinder来接收处理绑定到控制器方法上,调试源码并不是那么明朗,我们直接再自定义实现一个ComplexObjectModelBinderProvider,其具体ComplexObjectModelBinder有个方法BindPropertiesAsync,这是实际做相关处理的地方

/// <summary>
/// Create a property model name with a prefix.
/// </summary>
/// <param name="prefix">The prefix to use.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The property model name.</returns>
public static string CreatePropertyModelName(string? prefix, string? propertyName)
{
if (string.IsNullOrEmpty(prefix))
{
return propertyName ?? string.Empty;
} if (string.IsNullOrEmpty(propertyName))
{
return prefix ?? string.Empty;
} if (propertyName.StartsWith('['))
{
// The propertyName might represent an indexer access, in which case combining
// with a 'dot' would be invalid. This case occurs only when called from ValidationVisitor.
return prefix + propertyName;
} return prefix + "." + propertyName;
}

好了,到了这里我们只是知道了框架就是这么做的处理导致值绑定不上,问题又来了,请思考框架这么设计的初衷和思想是什么呢,框架为我们考虑了诸多场景。我们删除上述所有自定义实现, 框架以为我们想要达到如下绑定目的,但没曾想剑走偏锋,实际被我们钻了个空子,正所谓你以为的是你以为的并不是我以为的,然后一脸懵波

举一反三

还没完,继续开课,我们分析完整个前因后果后,我们终于明白了IValueProvider接口中所说的前缀具体指的是什么意思,然后对于前缀匹配使用二分法算法,同理,我们也不难看出,上述是对象绑定处理,在相同条件下,对于集合亦是如此。

总结

当进行查询操作时请求URL上的键名称若和后台接收参数变量名称相同且不区分大小写,框架以为我们想要使用接收参数变量作为前缀来绑定值,在相同等等条件下,对于集合亦是如此,除非我们自定义实现一套,否则我们万不可将其定义为相同名称,如此会导致值绑定不上。

翻译

搜索

复制

你所不知道的ASP.NET Core进阶系列(三)的更多相关文章

  1. 你所不知道的ASP.NET Core MVC/WebApi基础系列(一)

    前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时间也是一直在看ASP.NET Core的内容,所以后续会穿插讲EF Core和ASP.NET Core,别认为你会 ...

  2. 你所不知道的ASP.NET Core MVC/WebApi基础系列 (一)

    转自博客:https://www.cnblogs.com/CreateMyself/p/9235968.html 前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时 ...

  3. 你所不知道的ASP.NET Core MVC/WebApi基础系列(二)

    前言 好久没冒泡了,算起来估计有快半年没更新博客了,估计是我第一次停更如此之久,人总有懒惰的时候,时间越长越懒惰,但是呢,不学又不行,持续的惰性是不行dei,要不然会被时光所抛弃,技术所淘汰,好吧,进 ...

  4. 你所不知道的ASP.NET Core MVC/WebApi基础系列 (二)

    转自博客:https://www.cnblogs.com/CreateMyself/p/10604293.html 前言 本节内容,我们来讲讲.NET Core当中的模型绑定系统.模型绑定原理.自定义 ...

  5. Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它

    Asp.Net Core 提供了默认的依赖注入容器 IServiceCollection,它是一个轻量级的依赖注入容器,所以功能不多,只是提供了基础的一些功能,要实现AOP就有点麻烦,因此在实际工作当 ...

  6. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

  7. js值----你所不知道的JavaScript系列(6)

    1.数组 在 JavaScript 中,数组可以容纳任何类型的值,可以是字符串.数字.对象(object),甚至是其他数组(多维数组就是通过这种方式来实现的) .----<你所不知道的JavaS ...

  8. js类型----你所不知道的JavaScript系列(5)

    ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型.也有其他的叫法,比如原始类型和对象类型等. 1.内置类型 JavaScript 有七种内置类型: • 空值(null) • 未定义( ...

  9. 闭包----你所不知道的JavaScript系列(4)

    一.闭包是什么? · 闭包就是可以使得函数外部的对象能够获取函数内部的信息. · 闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. · 闭包就 ...

  10. 你真的会玩SQL吗?你所不知道的 数据聚合

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

随机推荐

  1. Linux系统文件(万物皆文件)

    -bin :基础命令文件,为usr下的bin文件连接 -boot :启动文件 -dev :device 设备目录  各种硬件设备都会映射成文件 -etc :系统管理的配置文件,和一些数据库文件 -ho ...

  2. 建设数字工厂:MRP物料需求计划的逻辑原理与配置方法

    本文分享自华为云社区<数字工厂深入浅出系列(七): MRP物料需求计划的逻辑原理与配置方法>,作者:云起MAE. MRP是生产制造企业"管好"物料的核心工具方法,基本思 ...

  3. python-多继承构造函数声明问题

    背景 有场景分别定义两组逻辑,随后有统一入口做基类属性的整合 其中两组逻辑的积累构造函数定义入参不同 设计类继承图如: 实际的使用方式抽象为[使用] 小节 实际开发过程中遇到问题 先说结论 pytho ...

  4. 论文解读(DWL)《Dynamic Weighted Learning for Unsupervised Domain Adaptation》

    [ Wechat:Y466551 | 付费咨询,非诚勿扰 ] 论文信息 论文标题:Dynamic Weighted Learning for Unsupervised Domain Adaptatio ...

  5. 静态vlan的划分

    静态vlan的划分 1,toupu图 2,配置id与子网掩码 2.1,pc,server的ip与子网配置 pc5 pc6 pc7 pc8 server1 server2 3,vlan的静态划分 1,v ...

  6. ACl与ACL实验

    ACl与ACL实验 ACL 1,ACL概述及 产生的背景 ACL: access list 访问控制列表 2,ACL应用 ACL两种应用: 应用在接口的ACL-----过滤数据包(原目ip地址,原目 ...

  7. 【SQL】所谓的连表查询

    连表查询 外连接 外连接分为两种,左(外)连接和右(外)连接 基本语法如下: SELECT 字段列表 FROM 表1 LEFT JOIN 表2 ON 条件; 这是左连接,因此以表1中的 [字段列表] ...

  8. 【krpano】KRPano自动缩略图分组插件

    该插件可以展示场景缩略图,并支持场景分组. 下载地址:http://pan.baidu.com/s/1dFj7v0l 使用说明: 插件共有两个文件,auto_thumbs.xml和tooltip.xm ...

  9. mysql触发器使用教程-六种触发器

    参考:https://zhuanlan.zhihu.com/p/439273702 触发器(Trigger)是 MySQL 中非常实用的一个功能,它可以在操作者对表进行「增删改」 之前(或之后)被触发 ...

  10. Redis面试——Redis面试精华知识

    从:Redis 使用场景与介绍 -> 数据结构与简单使用 -> 小功能大用处 -> 持久化.主从同步与缓存设计 -> 知识拓展 ,并且分析典型场景下常见的问题,并结合实战演练, ...