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]明確標識,不然你懂的。

相關文章
相關標籤/搜索