過去介紹過用jQuery傳件物件陣列字串陣列到ASP.NET MVC,採取的格式一直都還是application/x-www-form-urlencoded,遇到物件陣列時會編碼成players[0][Id]=...&players[0][Name]=..;JSON是當今傳輸轉換格式的主流,比起Form UrlEncode更直覺易偵錯,如要進行客製有豐富的現成程式庫,是更佳的選擇。

要以JSON格式傳送物件給ASP.NET MVC,除POST內容需為JSON字串,更重要的是HTTP Header的Content-Type必須設為application/json,才能被正確識別並反序列化還原為Server端物件。$.post()不能指定contentType,因此需改用底層的$.ajax(),我習慣仿效$.post()寫成$.postJson(),差別只在於傳送的資料物件會經JSON.stringify()序列化並將contentType指定為appliction/json,其餘呼叫應用方式則與$.post()一致。

用個範例說明,要傳送的Player類別如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace Lab1219.Models
{
    public class Player
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime RegDate { get; set; }
        public int Score { get; set; }
 
        public string ToText()
        {
            return string.Format("I:{0} N:{1} R:{2:yyyy-MM-dd} S:{2:n0}",
                Id, Name, RegDate, Score);
        }
    }
}

View有兩點補充: 1) 先前提過的$.postJson()函式,用起來$.post()一模一樣   2) RegDate宣告日期時用Date.UTC()指定UTC時區。

 
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        <input type="button" id="bSend" value="Test" />
    </div>
    <script src="~/Scripts/jquery-2.0.3.js"></script>
    <script>
        //以application/json ContentType傳送JSON字串到Server端
        jQuery.postJson = function (url, data, callback, type) {
            if (jQuery.isFunction(data)) {
                type = type || callback;
                callback = data;
                data = undefined;
            }
 
            return jQuery.ajax({
                url: url,
                type: "POST",
                dataType: type,
                contentType: "application/json",
                data: typeof(data) == "string" ? data : JSON.stringify(data),
                success: callback
            });
        };
    </script>
    <script>
        $("#bSend").click(function () {
            var players = [{
                Id: 1000, Name: "Darkthread",
                RegDate: new Date(Date.UTC(2000, 0, 1)),
                Score: 32767
            }, {
                Id: 1024, Name: "Jeffrey",
                RegDate: new Date(Date.UTC(2000, 0, 1)),
                Score: 9999
            }];
 
            $.postJson("@Url.Content("~/home/send")", players, function (res) {
                alert(res);
            });
        });
    </script>
</body>
</html>

Controller方面只有一點補充,參數players前方要加上[FromBody] Attribute,請ASP.NET MVC由POST傳送的內容本體解析參數,餘下的工作細節ASP.NET MVC自會搞定。

using Lab1219.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
 
namespace Lab1219.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ActionResult Index()
        {
            return View();
        }
 
        public ActionResult Send([FromBody]Player[] players)
        {
            return Content(string.Join("\n",
                players.Select(o => o.ToText()).ToArray()));
        }
    }
}

執行結果如下,這樣就能實現以JSON格式傳送參數給ASP.NET MVC。

檢查傳送內容,驗明POST內容確實為JSON無誤,大功告成。


Comments

# by 小黑

請問黑大, 文中程式碼,有一段 "@Url.Content("~/home/send")", 測試中,若 JS 是使用 link 檔案的方式,似乎會失效,不知黑大是否有法可解?

# by Jeffrey

to 小黑,我常用的解法是在cshtml中加一段window.appRoot="@Url.Content("~/")",在JS中再取得appRoot變數組裝路徑,由於用到的地方很多,多半會再進一步提取寫成$.mapPath('~/blah')之類的共用函式。

# by 小黑

謝謝黑大指點

# by ChengHao

第五行 $.post()並能指定contentType 應該是要打"不"能指定吧?

# by Jeffrey

to ChengHao, 是的,已修改,感謝指正。

Post a comment