ASP.NET Core MVC/WebAPi 模型绑定探索

简介:

前言

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

话题

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

ASP.NET MVC模型绑定

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

复制代码
    public class Person
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public int Age { get; set; }
    }
复制代码

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

        [HttpPost]
        public JsonResult PostPerson(Person p)
        {
            return Json(p);
        }

到这里,后台就大概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中绑定的方式。此时只需给出前台页面了。

复制代码
      <form id="form">
        <div class="form-group">
            <div class="control-label col-md-2">名称:</div>
            <div class="col-md-10">
                <input name="Name" id="Name" class="form-control" />
            </div>
        </div>
        <div class="form-group">
            <div class="control-label col-md-2">年龄:</div>
            <div class="col-md-10">
                <input name="Age" id="Age" class="form-control" />
            </div>
        </div>
        <div class="form-group">
            <div class="control-label col-md-2">家乡地址:</div>
            <div class="col-md-10">
                <input name="Address" id="Address" class="form-control" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="button" id="btnForm" value="MVC提交表单" class="btn btn-success" />
                <input type="button" id="btnJson" value="WebAPi提交" class="btn btn-warning" />
            </div>
        </div>
    </form>
复制代码

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

复制代码
           $("#btnForm").on("click", function () {
                var dataform = $('form').serialize();
                $.ajax({
                    url: "../MVC/PostPerson",
                    contentType: "application/x-www-form-urlencoded;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: dataform,
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
复制代码

 

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

复制代码
             $("#btnForm").on("click", function () {
                $.ajax({
                    url: "../MVC/PostPerson",
                    contentType: "application/json;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: JSON.stringify(datajson),
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
复制代码

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

ASP.NET WebAPi模型绑定

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

复制代码
           $("#btnJson").on("click", function () {
                var dataform = $('form').serialize();
                console.log(dataform);
                $.ajax({
                    url: "../api/WebAPi/PostPerson",
                    contentType: "application/x-www-form-urlencoded;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: dataform,
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
复制代码

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

复制代码
             $("#btnJson").on("click", function () {
                var datajson = { Name: "Jeffcky", Age: 24, Address: "湖南省" };
                console.log(datajson);
                $.ajax({
                    url: "../api/WebAPi/PostPerson",
                    contentType: "application/x-www-form-urlencoded;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: datajson,
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
复制代码

上述我们看到在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方法下添加如下一句来启用静态文件:

 app.UseStaticFiles();

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

复制代码
   [Route("[controller]")]
    public class HomeController : Controller
    {
        [HttpGet("Index")]
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost("PostPerson")]
        public IActionResult PostPerson(Person p)
        {
            return Json(p);
        }
    }
复制代码

此时加载页面如下:

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

复制代码
        $(function () {
            $("#btn").on("click", function () {
                var dataform = $('form').serialize();
                console.log(dataform);
                $.ajax({
                    url: "../Home/PostPerson",
                    contentType: "application/x-www-form-urlencoded;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: dataform,
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
        });        
复制代码

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

复制代码
        var datajson = { Name: "Jeffcky", Age: 24, Address: "湖南省" };
        $(function () {
            $("#btn").on("click", function () {
                console.log(datajson);
                $.ajax({
                    url: "../Home/PostPerson",
                    contentType: "application/json;charset=utf-8",
                    dataType: "json",
                    type: "post",
                    data: JSON.stringify(datajson),
                    success: function (data) {
                        console.log(data);
                    }
                });
            });
        });
复制代码

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

        [HttpPost("PostPerson")]
        public IActionResult PostPerson([FromBody]Person p)
        {
            return Json(p);
        }

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

 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该如何是好呢?我们只能写两个方法。如下:

复制代码
        [HttpPost("PostFormPerson")]
        public IActionResult PostFormPerson(Person p)
        {
            return Json(p);
        }

        [HttpPost("PostJsonPerson")]
        public IActionResult PostJsonPerson([FromBody] Person p)
        {
            return Json(p);
        }
复制代码

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

复制代码
        [HttpPost("PostPerson")]
        public IActionResult PostFormPerson(Person p)
        {
            return Json(p);
        }

        [HttpPost("PostPerson")]
        public IActionResult PostJsonPerson([FromBody] Person p)
        {
            return Json(p);
        }
复制代码

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

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

总结

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







本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/6246977.html,如需转载请自行联系原作者


目录
相关文章
|
4天前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
80 0
|
4天前
|
开发框架 .NET
ASP.NET Core NET7 增加session的方法
ASP.NET Core NET7 增加session的方法
40 0
|
4天前
|
开发框架 JavaScript .NET
ASP.NET Core的超级大BUG
ASP.NET Core的超级大BUG
47 0
|
4天前
|
域名解析 缓存 Linux
如何让你的.NET WebAPI程序支持HTTP3?
如何让你的.NET WebAPI程序支持HTTP3?
54 2
如何让你的.NET WebAPI程序支持HTTP3?
|
4天前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
48 0
|
4天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
23 0
|
4天前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
100 0
|
4天前
|
前端开发
.net core mvc获取IP地址和IP所在地(其实是百度的)
.net core mvc获取IP地址和IP所在地(其实是百度的)
128 0
|
4天前
|
开发框架 .NET Java
ASP.NET Core高级编程--C#基本特性(一)
本文章简略介绍C#的部分特性
|
4天前
|
JSON 开发框架 .NET
ASP.NET Core Web API设置响应输出的Json数据格式的两种方式
ASP.NET Core Web API设置响应输出的Json数据格式的两种方式