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]明确标识,否则你懂的。

目录
相关文章
|
小程序 iOS开发
微信小程序下载文件和转发文件给好友总结
微信小程序下载文件和转发文件给好友总结
3067 0
微信小程序下载文件和转发文件给好友总结
|
存储 JSON 开发工具
三、HarmonyOS NEXT应用开发:ArkTS工程目录结构(Stage模型)
本文介绍了HarmonyOS NEXT应用开发中ArkTS工程的目录结构(Stage模型),包括AppScope、entry、hvigor、oh_modules等主要目录及其作用。重点解析了entry目录下的src > main > resources目录结构,详细说明了base、限定符目录和rawfile的作用,以及如何引用资源文件。
1439 1
|
人工智能 弹性计算 算法
【云故事探索】NO.5:PETKIT小佩,科技与爱,共绘宠物智能生活新篇章
在数字化浪潮中,中国宠物行业蓬勃发展,国内养宠规模已超2亿,形成千亿市场。成立于2013年的PETKIT小佩,专注智能宠物用品,服务遍布40+国家。面对618、双11等高峰挑战,阿里云ECS弹性扩容助其稳定运行。借助阿里云全球化部署能力,小佩成功出海。最新可视喂食器结合AI算法与OSS存储,提升用户体验。未来,双方将进一步探索AI大模型在宠物行业的应用,持续优化养宠体验。
Windows中如何查看被占用的端口、杀掉对应的进程
这篇文章介绍了在Windows系统中如何查看被占用的端口号以及如何杀掉占用端口的进程,包括使用命令提示符的`netstat -ano | findstr 端口号`命令查找进程PID,然后通过任务管理器或`taskkill /PID PID号`命令来结束进程。
Windows中如何查看被占用的端口、杀掉对应的进程
|
人工智能 小程序 机器人
微信小程序如何接入天气预报查询 API(内附实战代码)
最近在准备面试,打算做一个天气预报查询的小程序来丰富自己的简历,在这里整理了一下我接入的过程,分享给大家也方便自己日后使用,强烈建议收藏!!!
|
Java 数据库连接 数据库
Hibernate学习笔记8,session管理,事务控制
Hibernate学习笔记8,session管理,事务控制 Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰。
1935 0
|
10天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7768 13
|
8天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1681 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!

热门文章

最新文章