ASP.NET Core MVC 模型绑定用法及原理
前言
查询了一下关于 MVC 中的模型绑定,大部分都是关于如何使用的,以及模型绑定过程中的一些用法和概念,很少有关于模型绑定的内部机制实现的文章,本文就来讲解一下在 ASP.NET Core MVC 中模型绑定是如何实现的,以及它的一些其他用法。
模型绑定的用途
通常情况下,我们在使用 MVC 框架的时候不需要关注模型绑定的相关功能,因为它是集成到 MVC 框架内部的,当我们在浏览器访问一个地址的时候,无论是 GET 还是 POST 访问,在映射到 Action 的过程中 MVC 框架已经自动的进行了对象或者是路由参数的绑定,这其中就是使用的模型绑定。
在 ASP.NET Core MVC 中,模型绑定分为简单模型绑定和复杂模型绑定。简单的模型绑定比如直接从 Form 表单或者 URL 路由数据中获取信息,然后应用到Action方法的各个参数上,复杂模型绑定的话可能就不是简单的转换到参数的值上面了,可能中间还会涉及到一些数据类型转换,模型分解,参数校验等。
下面来看一下模型绑定的一个示例:
假设我们有一个ViewModel对象叫 Person
,它的代码如下:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
在这个 ViewModel 对象中,都是使用的一些很简单的类型,那么我们的 Action 进行如下的定义:
public class PersonController
{
[HttpPost]
[Route("~api/person/add")]
public IActionResult CreatePerson(Person person)
{
return Ok(person);
}
}
在上面的代码中,我们可以向 http://localhost:5000/api/person/add
这个地址发送一个 POST 请求,Body 类型使用普通的 Form ,参数使用上面Person
定义的 Name
, Age
。 在 Action 上添加断点,我们就可以看到person变量中的值,然后此 Action 会返回一个被 json 序列化后的结果对象。
这样一个过程,就是模型绑定在实际开发中的一个用途和用法。
是不是看起来很简单呢?但是在内部模型绑定子系统是比较复杂的,由很多部分组成。
模型绑定的一些用法
在 ASP.NET Core MVC 中,支持以下表单类型的模型绑定。
[FromHeader]
,[FromQuery]
,[FromRoute]
,[FromForm]
示例:
public IActionResult CreatePerson([FromForm]Person person)
{
return Ok(person);
}
这些 [FromXXX]
是告诉模型绑定在解析的过程中从HttpContext中那一部分获取信息。
还有一部分模型绑定框架中定义的一些 Attribute 是用来在模型模型的过程中限制或者忽略一些参数。比如
[BindRequired]
,[BindNever]
这两个是用来在模型绑定的过程中添加的一些制约,BindRequired
可以应用在类或者属性上,用来限制在绑定的过程中必须需要的一些值。BindNever
用来忽略当前参数的绑定。
还有两个 [FromServices]
, [FromBody]
。
[FromServices]
是参数绑定的过程中,告诉模型绑定框架该参数从 DI 容器中获取。
[FromBody]
是参数绑定的过程中,告诉框架该参数是使用配置过的格式化程序从Http Body 中解析。
在[FromBody]中,默认情况下会使用MVC框架内部配置的 JsonInputFormatter 进行反序列化解析,如果你传递的 Body 中的类型是 application/xml,你可以在 ConfigureServices 方法中配置
services.AddMvc().AddXmlSerializerFormatters();
进行XML的反序列化。
还有一个 [ModelBinder]
这个可能很多人没用过,这个是应用在 Controller 中的属性上的,用来绑定属性信息。比如
public class Controller
{
[ModelBinder]
public string Name { get; set;}
public IActionResult CreatePerson(Person person)
{
return Ok(person);
}
}
在 Action 激活的时候,Controller 的 Name 属性也会具有Action 参数中 person 变量中名字和 Name 相同参数的值。
自定义模型绑定
自定义模型绑定属于 MVC 模型绑定的一些高级知识,在一些特殊情况中我们可能会使用到他们。 详情可以参考这篇 文章 https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding,本文不打算做过多介绍。
MVC 模型绑定(ModelBinding)实现原理
看过我 ASP.NET Core MVC Action 激活 这篇文章的同学应该知道,在 Action 激活的过程中会涉及到很多状态,那么模型绑定是在 ActionBegin
这个状态中进行的,同时在 ActionNext
过程中被使用,我就直接接着这篇文章的 Action 执行部分进行讲解了。
首先,模型绑定的入口位于 ControllerActionInvoker
这个类中的一个Next方法里
private Task Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted){
......
switch (next)
{
case State.ActionBegin:
BindArgumentsAsync();
goto case State.ActionNext;
case State.ActionNext:
_actionExecutingContext = new ActionExecutingContext(_arguments);
}
......
}
可以看到在 State.ActionBegin
这个过程中使用了 BindArgumentsAsync()
进行参数绑定,那么整个绑定过程就由此开始。
在 Core MVC 框架模型绑定部分源码中,模型绑定源码分为这几部分:元数据(Metadata),值提供器(ValueProvider),验证者(Validator),绑定器(Binder)。
元数据:元数据相当于模型绑定中的实体对象,用来储存在整个模型绑定子系统中需要的各种必要信息和元数据信息,包括模型参数的元数据和以及绑定信息的元数据等等。
值提供器:值提供器用来提供在运行时模型绑定器可以从中提取值的一个Provider, 默认情况下,值提供器会从以下地方提取各种资源的值:
1、以前绑定的操作参数(当该操作为子操作时)
2、表单字段 (FormValueProvider)
3、路由数据 (RouteValueProvider)
4、查询字符串参数 (QueryStringValueProvider)
5、JQuery 表单数据(JQueryFormValueProvider)
这些 ValueProvider 对象由 CompositeValueProvider
进行统一管理,它是一个集合用来创建或者获取这些 ValueProvider 对象。
验证者:验证者是用来验证Action参数中模型字段的合法性。
它的默认实现是 DefaultObjectValidator
,它会根据元数据信息来确定绑定过程中使用的具体 ValudatorProvider 对象,ValudatorProvider 是用来提供IModelValidator
接口实例对象的。
在 ASP.NET Core MVC 中有两个类实现了 IModelValidator
接口,他们分别是 DataAnnotationsModelValidator
和 ValidatableObjectAdapter
。 其中 ValidatableObjectAdapter
是一个适配器,用来转换和封装验证结果,所以我们主要看 DataAnnotationsModelValidator
。
DataAnnotationsModelValidator
就是用来验证模型类中的各种 Attribute 的,也就是DataAnnotations
相关的那些类,比如 [MaxLength]
,[Required]
,[RegularExpression]
等等。
绑定器: 绑定器用来绑定Action参数中的大多数简单和复杂的数据模型,它通过对模型各个属性使用递归逻辑来实现该目标。
针对不同类型的绑定具有不同的绑定器,如:
ArrayModelBinder
,SimpleTypeModelBinder
,FormFileModelBinder
,
FormCollectionModelBinder
,ComplexTypeModelBinder
,
BodyModelBinder
,HeaderModelBinder
,DictionaryModelBinder
,
ServicesModelBinder
,KeyValuePairModelBinder
,ByteArrayModelBinder
,
CancellationTokenModelBinder
,CollectionModelBinder
,BinderTypeModelBinder
这些 ModelBinder 对象都具有各自的 Provider 对象,对来返回当前Binder对象的实例对象。
这些 ModelBinder 对象由 ParameterBinder
进行统一管理, ParameterBinder
对象会接收模型的元数据信息(Metadata),绑定器工厂(BinderFactory),验证者(Validator),然后进行最终的模型绑定流程,如下图:
回到总流程
我们回到 ControllerActionInvoker
这个中,BindArgumentsCoreAsync
这个函数中会进行上层的模型绑定,流程如下:
以上总流程的前两步就是 MVC Core 模型绑定系统针对于 Controller 中 Action 参数的绑定,实际上除了针对 Action 参数绑定外,还会对 Controller 中的使用了 [IModelBinder]
特性的进行绑定,那么第三步就是在做这个事情。
至此,模型绑定流程结束。
总结
在本篇中,我们学习了在 ASP.NET Core MVC 中模型绑定的一些用途和一些基本的用法,然后学习了 MVC框架中模型绑定的一些内部实现原理,通过这个学习我们可以对整个模型绑定系统更加的系统的一个了解,以便于我们有在工作系统的时候可以针对于模型绑定系统进行扩展。
如果你觉得本篇博客对你有帮助的话,感谢您的【推荐】。
如果你对 ASP.NET Core 有兴趣的话可以关注我,我会定期的在博客分享我的学习心得。
本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-modelbinding.html
作者博客:Savorboard
欢迎转载,请在明显位置给出出处及链接
ASP.NET Core MVC 模型绑定用法及原理的更多相关文章
- ASP.NET Core MVC 模型绑定 (转载)
ASP.NET Core MVC的Model Binding会将HTTP Request数据,以映射的方式对应到参数中.基本上跟ASP.NET MVC差不多,但能Binding的来源更多了一些.本篇将 ...
- .net core mvc 模型绑定 之 json and urlencoded
.net core mvc 模型绑定, FromQuery,对应 url 中的 urlencoded string ("?key1=value1&key2=value2") ...
- ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览
原文:Overview of ASP.NET Core MVC 作者:Steve Smith 翻译:张海龙(jiechen) 校对:高嵩 ASP.NET Core MVC 是使用模型-视图-控制器(M ...
- ASP.NET Core MVC 概述
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/overview?view=aspnetcore-2.2 ASP.NET Core MVC 概述 20 ...
- 你所不知道的ASP.NET Core MVC/WebApi基础系列(二)
前言 好久没冒泡了,算起来估计有快半年没更新博客了,估计是我第一次停更如此之久,人总有懒惰的时候,时间越长越懒惰,但是呢,不学又不行,持续的惰性是不行dei,要不然会被时光所抛弃,技术所淘汰,好吧,进 ...
- 你所不知道的ASP.NET Core MVC/WebApi基础系列 (二)
转自博客:https://www.cnblogs.com/CreateMyself/p/10604293.html 前言 本节内容,我们来讲讲.NET Core当中的模型绑定系统.模型绑定原理.自定义 ...
- ASP.NET Core 入门教程 3、ASP.NET Core MVC路由入门
一.前言 1.本文主要内容 ASP.NET Core MVC路由工作原理概述 ASP.NET Core MVC带路径参数的路由示例 ASP.NET Core MVC固定前/后缀的路由示例 ASP.NE ...
- Pro ASP.NET Core MVC 第6版 第一章
目录 第一章 ASP.NET Core MVC 的前世今生 ASP.NET Core MVC 是一个微软公司开发的Web应用程序开发框架,它结合了MVC架构的高效性和简洁性,敏捷开发的思想和技术和.N ...
- ASP.NET Core 入门笔记4,ASP.NET Core MVC路由入门
敲了一部分,懒得全部敲完,直接复制大佬的博客了,如有侵权,请通知我尽快删除修改 摘抄自https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc ...
随机推荐
- Uva 11029 Leading and Trailing (求n^k前3位和后3位)
题意:给你 n 和 k ,让你求 n^k 的前三位和后三位 思路:后三位很简单,直接快速幂就好,重点在于如何求前三位,注意前导0 资料:求n^k的前m位 博客连接地址 代码: #include < ...
- 解决 eclipse buildpath的jar包不能复制到tomcat lib下的问题
环境: Eclipse 版本 Mars. 问题描述: Eclipse 开发的JavaWeb项目,通过buildpath的引入的jar包无法发布到tomcat对应应用的Lib 下. 解决办法: 1. 手 ...
- codevs2019 Uva10029 递变阶梯
提交地址:[codevs][Uva] 题目描述 递变是指通过增加.减少或改变单词x中的一个字母,使它变成字典中的另一个单词y.比如将dig变成dog,将dog变成do都是递变.递变阶梯是一个按字典序 ...
- /etc/postfix下 main.cf 配置文件详解
postconf -n #别名数据库(postalias/newaliases 命令生成) alias_database = hash:/etc/postfix/aliases #别名表,列出 ...
- 原生JavaScript实现焦点图轮播
不管是高校的网站还是电商的页面,焦点图的切换和轮播应该是一项不可或缺的应用.今天把焦点图轮播制作的技术要点做下笔记,以供日后查看. 一.结构层(HTML) 焦点图的HTML结构很简单,就是一个父容器( ...
- ## Python中的Package和Jupyter中import包问题
前言 关于python包的一些知识 Java中的package概念 我们知道在java中的import package概念, java中的包就是一个目录,里面包含着子目录,子目录套着子目录,当需要引入 ...
- yii框架数据库操作数据访问对象(DAO)简单总结
Yii提供了强大的数据库编程支持.Yii数据访问对象(DAO)建立在PHP的数据对象(PDO)extension上,使得在一个单一的统一的接口可以访问不同的数据库管理系统(DBMS).使用Yii的DA ...
- 使用EzHttp框架 开发基于HTTP协议的CS轻应用
框架概述 EzHttp是临时起意构思和开发的一个框架,目的在于简化CS轻应用开发过程.开发语言是C#. 普通的基于HTTP的应用开发基本上是RESTful的,客户端调用封装需要人工写代码,就算利用三方 ...
- nginx参数的详细说明
#开启进程数 <=CPU数 worker_processes 1; #错误日志保存位置 #error_log logs/error.log; #error_log logs/error.log ...
- google ip地址
http://203.208.46.146 http://203.208.46.177 http://203.208.46.178 http://209.116.186.251 http://203. ...