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

前言

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

话题

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

ASP.NET MVC模型绑定

咱们首先仍是老规矩给出测试类json

    public class Person
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public int Age { get; set; }
    }

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

        [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将进行绑定。app

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

请求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]明确标识,不然你懂的。

相关文章
相关标签/搜索