前言

相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用到了,你再去看理论性的文章时才会豁然开朗,这是我一直以来学习技术的方法。本文我们来讲解.NET Core中的模型绑定。

话题

在ASP.NET Core之前MVC和Web APi被分开,也就说其请求管道是独立的,而在ASP.NET Core中,WebAPi和MVC的请求管道被合并在一起,当我们建立控制器时此时只有一个Controller的基类而不再是Controller和APiController。所以才有本节的话题在模型绑定上呈现出有何不同呢?下面我们一起来看看。

ASP.NET MVC模型绑定

我们首先还是老规矩给出测试类

  1. public class Person
  2. {
  3. public string Name { get; set; }
  4. public string Address { get; set; }
  5. public int Age { get; set; }
  6. }

接着POST请求通过Action方法进行模型绑定。

  1. [HttpPost]
  2. public JsonResult PostPerson(Person p)
  3. {
  4. return Json(p);
  5. }

到这里,后台就大概over了,是不是就这么完了呢,我们一直在强调模型绑定这个词语,那么到底什么是模型绑定呢,有必要解释下。我们PostPerson这个方法中有一个Person的变量参数,那么问题来了,前台发出请求到这个方法从而该参数接收到传递过来的数据从而进行响应,这个p到底是怎么接收到的呢,恩,通过模型绑定呗,为了将数据聚合到对象或者其他简单的参数可以通过模型绑定来查找数据,常见的绑定方式有如下四种。

路由值(Route Values):通过导航到路由如{controller}/{action}/{id}此时将绑定到id参数。

查询字符串(QueryStrings):通过查询字符串中的参数来绑定,如name=Jeffcky&id=1,此时name和id将进行绑定。

请求Body(Body):通过在POST请求中将数据传入到Body中此时将绑定如上述Person对象中。

请求Header(Header):绑定数据到Http中的请求头中,这种相对来说比较少见。

所以通过上述讲述我们知道有多种方式将数据从客户端传递到服务端,然后模型绑定会自动为我们创建正确的方法来绑定到后台参数中,简单和复杂的类型参数都会进行绑定。

接下来我们来演示在ASP.NET MVC中绑定的方式。此时只需给出前台页面了。

  1. <form id="form">
  2. <div class="form-group">
  3. <div class="control-label col-md-2">名称:</div>
  4. <div class="col-md-10">
  5. <input name="Name" id="Name" class="form-control" />
  6. </div>
  7. </div>
  8. <div class="form-group">
  9. <div class="control-label col-md-2">年龄:</div>
  10. <div class="col-md-10">
  11. <input name="Age" id="Age" class="form-control" />
  12. </div>
  13. </div>
  14. <div class="form-group">
  15. <div class="control-label col-md-2">家乡地址:</div>
  16. <div class="col-md-10">
  17. <input name="Address" id="Address" class="form-control" />
  18. </div>
  19. </div>
  20. <div class="form-group">
  21. <div class="col-md-offset-2 col-md-10">
  22. <input type="button" id="btnForm" value="MVC提交表单" class="btn btn-success" />
  23. <input type="button" id="btnJson" value="WebAPi提交" class="btn btn-warning" />
  24. </div>
  25. </div>
  26. </form>

首先我们提交表单形式来传输数据。

  1. $("#btnForm").on("click", function () {
  2. var dataform = $('form').serialize();
  3. $.ajax({
  4. url: "../MVC/PostPerson",
  5. contentType: "application/x-www-form-urlencoded;charset=utf-8",
  6. dataType: "json",
  7. type: "post",
  8. data: dataform,
  9. success: function (data) {
  10. console.log(data);
  11. }
  12. });
  13. });

然后我们通过传输JSON的数据同样来发出POST请求。

  1. $("#btnForm").on("click", function () {
  2. $.ajax({
  3. url: "../MVC/PostPerson",
  4. contentType: "application/json;charset=utf-8",
  5. dataType: "json",
  6. type: "post",
  7. data: JSON.stringify(datajson),
  8. success: function (data) {
  9. console.log(data);
  10. }
  11. });
  12. });

结果同样返回上述数据,就不再演示,下面我们看看WebAPi中的情况。

ASP.NET WebAPi模型绑定

当然上述利用JSON传输数据同样也适用于WebAPi,下面我们来看看利用查询字符串在WebAPi中的情况。

  1. $("#btnJson").on("click", function () {
  2. var dataform = $('form').serialize();
  3. console.log(dataform);
  4. $.ajax({
  5. url: "../api/WebAPi/PostPerson",
  6. contentType: "application/x-www-form-urlencoded;charset=utf-8",
  7. dataType: "json",
  8. type: "post",
  9. data: dataform,
  10. success: function (data) {
  11. console.log(data);
  12. }
  13. });
  14. });

我们再来看看在WebAPi中表单的形式。

  1. $("#btnJson").on("click", function () {
  2. var datajson = { Name: "Jeffcky", Age: 24, Address: "湖南省" };
  3. console.log(datajson);
  4. $.ajax({
  5. url: "../api/WebAPi/PostPerson",
  6. contentType: "application/x-www-form-urlencoded;charset=utf-8",
  7. dataType: "json",
  8. type: "post",
  9. data: datajson,
  10. success: function (data) {
  11. console.log(data);
  12. }
  13. });
  14. });

上述我们看到在ASP.NET MVC/WebAPi中无论是以表单POST的形式抑或JSON的形式控制器具有绑定都Http请求Body的能力同时数据都会返回给我们,我们不需要做出任何特别的说明,所以都没毛病。接下来我们来看看ASP.NET Core MVC/WebAPi中的模型绑定形式。

ASP.NET Core MVC/WebAPi

在ASP.NET Core中为了加载服务器的静态文件如css、js、文件等等记住需要在Startup.cs中的Configure方法下添加如下一句来启用静态文件:

  1. app.UseStaticFiles();

由于在ASP.NET Core中MVC和WebAPi请求管道合并,所以只有Controller基类,我们在控制器下建立如下方法:

  1. [Route("[controller]")]
  2. public class HomeController : Controller
  3. {
  4. [HttpGet("Index")]
  5. public IActionResult Index()
  6. {
  7. return View();
  8. }
  9.  
  10. [HttpPost("PostPerson")]
  11. public IActionResult PostPerson(Person p)
  12. {
  13. return Json(p);
  14. }
  15. }

此时加载页面如下:

接下来我们分别演示以表单形式和JSON形式来发出POST请求。

  1. $(function () {
  2. $("#btn").on("click", function () {
  3. var dataform = $('form').serialize();
  4. console.log(dataform);
  5. $.ajax({
  6. url: "../Home/PostPerson",
  7. contentType: "application/x-www-form-urlencoded;charset=utf-8",
  8. dataType: "json",
  9. type: "post",
  10. data: dataform,
  11. success: function (data) {
  12. console.log(data);
  13. }
  14. });
  15. });
  16. });

接下来我们再来看看传输JSON。

  1. var datajson = { Name: "Jeffcky", Age: , Address: "湖南省" };
  2. $(function () {
  3. $("#btn").on("click", function () {
  4. console.log(datajson);
  5. $.ajax({
  6. url: "../Home/PostPerson",
  7. contentType: "application/json;charset=utf-8",
  8. dataType: "json",
  9. type: "post",
  10. data: JSON.stringify(datajson),
  11. success: function (data) {
  12. console.log(data);
  13. }
  14. });
  15. });
  16. });

此时就和ASP.NET MVC/WebAPi中情况就不一样,此时后台接收不到数据,从而返回null。在ASP.NET Core中为了正确绑定到JSON我们需要在Action方法中对参数显式指定[FromBody]。

  1. [HttpPost("PostPerson")]
  2. public IActionResult PostPerson([FromBody]Person p)
  3. {
  4. return Json(p);
  5. }

通过使用[FromBody]则能正常使用了,那么到了这里你是不是就认为我们应该总是使用[FromBody]特性呢,如果你这样想就大错特错了,我们将上述contentType修改成表单形式

  1. contentType: "application/x-www-form-urlencoded;charset=utf-8",

此时会得到415不支持此媒体类型,当我们使用[FromBody]特性时,也就是明确告诉.NET Core要使用请求中的contentType头来决定输入参数对于模型绑定。默认情况下在我们注入MVC服务时被配置使用的时JsonInputFormatter,当然我们可以配置其他formatter比如xml,所以在这里我们将绑定到请求的Body中,但是输入参数不对,因为其格式为Name=Jeffcky&Age=24&Address=湖南省,所以会出现不支持该媒体类型,在这里我们要么去除[FromBody]特性,要么添加[FromForm]特性。如果我们既需要绑定表单也需要绑定JSON该如何是好呢?我们只能写两个方法。如下:

  1. [HttpPost("PostFormPerson")]
  2. public IActionResult PostFormPerson(Person p)
  3. {
  4. return Json(p);
  5. }
  6.  
  7. [HttpPost("PostJsonPerson")]
  8. public IActionResult PostJsonPerson([FromBody] Person p)
  9. {
  10. return Json(p);
  11. }

现在看来想想是不是没有之前ASP.NET MVC/WebAPi灵活和方便呢,微软是不是闲的蛋疼啊,所以我们是不是觉得虽然是两个方法我们将其路由定义成相同的,那么当我们在调用时让其自己去匹配不就得了,于是乎就有了如下的情况。

  1. [HttpPost("PostPerson")]
  2. public IActionResult PostFormPerson(Person p)
  3. {
  4. return Json(p);
  5. }
  6.  
  7. [HttpPost("PostPerson")]
  8. public IActionResult PostJsonPerson([FromBody] Person p)
  9. {
  10. return Json(p);
  11. }

此时还没到控制器下的路由方法就已经发生500错误了,如下:

好了看到这里我们本节的内容就已经接近尾声了,是不是觉得微软闲的没事干了,明明一个方法就可以ok的事,非得要我们写两个方法,原因到底是什么呢,据了解社区是为了安全考虑,主要原因是为了防止CSRF(Cross-Site Rquest Forgery)究竟内部到底是怎么防止CSRF的呢,不得而知,难道像之前MVC中的For...那样么,不得而知。

总结

本节我们比较详细的讨论了ASP.NET Core MVC/WebAPi中的模型绑定,如果在前台是JSON绑定,在ASP.NET Core MVC/WebAPi必须要用[FromBody]明确标识,否则你懂的。

ASP.NET Core MVC/WebAPi 模型绑定探索的更多相关文章

  1. ASP.NET Core MVC/WebAPi 模型绑定探索 转载https://www.cnblogs.com/CreateMyself/p/6246977.html

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  2. 【转】ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  3. ASP.NET Core MVC/WebAPi 模型绑定

    public class Person { public string Name { get; set; } public string Address { get; set; } public in ...

  4. ASP.NET Core MVC/WebAPi如何构建路由?

    前言 本节我们来讲讲ASP.NET Core中的路由,在讲路由之前我们首先回顾下之前所讲在ASP.NET Core中的模型绑定这其中有一个问题是我在项目当中遇见的,我们下面首先来看看这个问题. 回顾A ...

  5. ASP.NET Core 中的模型绑定

    微软官方文档:ASP.NET Core 中的模型绑定 Route 是通过MVC Route URL取值. 如:http://localhost:5000/Home/Index/2,id取出的值就会是2 ...

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

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

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

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

  8. ASP.NET Core MVC 之模型(Model)

    1.模型绑定 ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数.参数既可以是简单类型,也可以是复杂类型.MVC 通过抽象绑定解决了这个问题. 2.使用模型绑定 当 ...

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

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

随机推荐

  1. Linux安装LAMP开发环境及配置文件管理

    Linux主要分为两大系发行版,分别是RedHat和Debian,lamp环境的安装和配置也会有所不同,所以分别以CentOS 7.1和Ubuntu 14.04做为主机(L) Linux下安装软件,最 ...

  2. Git Bash的一些命令和配置

    查看git版本号: git --version 如果是第一次使用Git,你需要设置署名和邮箱: $ git config --global user.name "用户名" $ gi ...

  3. HTML BOM Browser对象

    BOM:Browser Object Model,即浏览器对象模型,提供了独立于内容的.可以与浏览器窗口进行互动的对象结构. Browser对象:指BOM提供的多个对象,包括:Window.Navig ...

  4. SQL Server-聚焦UNIOL ALL/UNION查询(二十三)

    前言 本节我们来看看有关查询中UNION和UNION ALL的问题,简短的内容,深入的理解,Always to review the basics. 初探UNION和UNION ALL 首先我们过一遍 ...

  5. [C#] 简单的 Helper 封装 -- CookieHelper

    using System; using System.Web; namespace ConsoleApplication5 { /// <summary> /// Cookie 助手 // ...

  6. OpenGL超级宝典笔记----渲染管线

    在OpenGL中任何事物都在3D空间中,但是屏幕和窗口是一个2D像素阵列,所以OpenGL的大部分工作都是关于如何把3D坐标转变为适应你屏幕的2D像素.3D坐标转为2D坐标的处理过程是由OpenGL的 ...

  7. WebGIS中等值面展示的相关方案简析

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 等值面是气象.环保等相关项目上常用到的效果展示.在传统的CS项 ...

  8. bcp 命令实例

    set sql_flow="select Id,',',ApplierName,',',FlowStatus,',',IsApproved,',',CreateTime from *** w ...

  9. CSS 3学习——transform 2D转换

    首先声明一点,transform属性不为none的元素是它的定位子元素(绝对定位和固定定位)的包含块,而且对内创建一个新的层叠上下文. 注意:可以通过 transform-box 属性指定元素的那个盒 ...

  10. 自己实现简单Spring Ioc

    IoC则是一种 软件设计模式,简单来说Spring通过工厂+反射来实现IoC. 原理简单说明: 其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外 ...