zoukankan      html  css  js  c++  java
  • [转]使用jQuery.ajax傳送物件陣列給ASP.NET MVC

    本文转自:http://blog.darkthread.net/post-2012-06-23-post-array-to-mvc-with-jquery-ajax.aspx

    在ASP.NET MVC裡,我們可以用物件集合當成Action的傳入參數,例如以下範例:

    排版顯示純文字
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
     
    namespace MvcMobileLab.Controllers
    {
        public class AjaxPostController : Controller
        {
            public ActionResult Index(string viewName)
            {
                if (string.IsNullOrEmpty(viewName))
                    return View();
                else
                    return View(viewName);
            }
            /// <summary>
            /// 測試用資料類別
            /// </summary>
            public class Player
            {
                public string Id { get; set; }
                public string Name { get; set; }
            }
            ///測試用Action,前端接入List<Player>,轉JSON後傳回
            public ActionResult Update(List<Player> players)
            {
                return Json(players);
            }
        }
    }

    在以上的Controller裡,定義了一個極簡單的Player資料類別,只有Id跟Name兩個屬性。假設有一個Update動作,可接收List<Player>作為輸入參數,為了示範,並不真的把players資料更新到資料庫,而是轉為JSON格式後回傳,讓前端驗證資料是否已正確傳達。

    在HTML Form裡要怎麼把List<Player>當成參數傳給Action呢? ASP.NET MVC內建的Model Binder已具備將特定規則參數對應成ICollection<T>的能力,方法可參考以下兩篇文章:

    簡單來說,ASP.NET MVC的Model Binder會從POST的欄位中用players[0].Id, players[0].Name去找players陣列第一個物件的各屬性,用players[1].*去對應第二個物件... 以此類推。因此,如果我們想用jQuery.ajax()呼叫Update(List<Player> players) Action,只要用{ "players[0].Id": "P01", "players[0].Name": "Jeffrey", "players[1].Id": "P02" ... }當成參數傳送,ASP.NET MVC就能正確解析與接收,例如以下範例:

    排版顯示純文字
    @{ Layout = null; }
    <!DOCTYPE html>
     
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Test</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js"></script>
        <script>
            $(function () {
                var data = {
                    "players[0].Id": "P01",
                    "players[0].Name": "Jeffrey",
                    "players[1].Id": "P02",
                    "players[1].Name": "Darkthread"
                };
                $.post("@Url.Content("~/AjaxPost/Update")", data, function(res) {
                    alert(JSON.stringify(res));
                }, "json");
            });
        </script>
    </head>
    <body>
    </body>
    </html>

    執行成功,前端可正確接回預期的List<Player>內容,驗證了用這種格式組合參數,ASP.NET MVC就能將我們傳送的內容解析成List<Player>!

    不過,在大量使用Javascript的網頁中,通常會用陣列來保存Player物件,例如: var players = [ { Id:"P01", Name:"Jeffrey" }, { Id:"P02", Name: "Darkthread" } ],不太可能寫成<input type="text" name="players[0].Id" />的形式。因此,較直覺得的寫法應是$.post(the_action_url, { players: players_array }, function(r) { … }, "json");,這樣能成功嗎?

    排版顯示純文字
    @{ Layout = null; }
    <!DOCTYPE html>
     
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Test</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js"></script>
        <script>
            $(function () {
                var array = [];
                array.push({ Id: "P01", Name: "Jeffrey" });
                array.push({ Id: "P02", Name: "Darkthread" });
                $.post(
                    "@Url.Content("~/AjaxPost/Update")", 
                    {  players: array }, 
                    function(res) {
                        alert(JSON.stringify(res));
                    }, 
                    "json"
                );
            });
        </script>
    </head>
    <body>
    </body>
    </html>

    結果很有趣,ASP.NET MVC判讀出它是個陣列,但是Player的屬性值沒抓到,都是null。

    實際觀察$.post()傳送的內容,可看出一些端倪...

    $.ajax()遇到傳送參數中有物件陣列時,也會拆解成palyers[0],players[1]的形式,但對於屬性值,並不是ASP.NET MVC所預期的players[0].Id,而是寫成players[0][Id]。追進jQuery原始碼,發現這是function buildParams( prefix, obj, traditional, add )被賦與的編碼邏輯,且沒有預留自訂規則的空間。由於players[0].Id與players[0][Id]只有格式上的些微差異,因此我想到一個做法是在jQuery.ajax()的beforeSend事件做手腳,將序列化完成字串中的players[0][Id]用Regular Expression置換成players[0].Id,於是順手寫了一個Plugin, $.postMvc(),攔截beforeSend事件,對buildParams()序列化後的字串進行陣列元素屬性名稱的置換,再傳送出去。要應用時,用$.post它來取代$.post()即可:

    排版顯示純文字
    @{ Layout = null; }
    <!DOCTYPE html>
     
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Test</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js"></script>
        <script>
            (function ($) {
                $.extend($, {
                    //Replace item[0][propName] to item[0].propName for MVC model binder
                    postMvc: function (url, data, succ, dataType) {
                        return $.ajax({
                            url: url,
                            type: "POST", dataType: dataType,
                            data: data,
                            success: succ,
                            beforeSend: function (xhr, settings) {
                                settings.data =                              settings.data.replace(/%5D%5B(.+?)%5D=/g, "%5D.$1=");
                            }
                        });
                    }
                });
            })(jQuery);
     
            $(function () {
                var array = [];
                array.push({ Id: "P01", Name: "Jeffrey" });
                array.push({ Id: "P02", Name: "Darkthread" });
                $.postMvc(
                    "@Url.Content("~/AjaxPost/Update")", 
                    {  players: array }, 
                    function(res) {
                        alert(JSON.stringify(res));
                    }, 
                    "json"
                );
            });
        </script>
    </head>
    <body>
    </body>
    </html>

    這樣子,就能很輕鬆地將Javascript物件陣列抛給ASP.NET MVC當List<T>參數囉~

    歡迎推文分享:
  • 相关阅读:
    2017.11.20 定时器与数码管
    2017.11.19 C语言基础及流水灯实现
    libcmtd.lib(exe_wwinmain.obj) : error LNK2001: 无法解析的外部符号 _wWinMain@16
    VCatlmfcincludeafx.h(24): fatal error C1189: #error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
    VS2015解决 error C4996: 'strdup': The POSIX name for this item is deprecated.
    vs2015单元测试
    pkg-config的一些用法
    CMake快速入门
    CMake入门教程
    Ubuntu16.04下安装NVIDIA显卡驱动
  • 原文地址:https://www.cnblogs.com/freeliver54/p/3079608.html
Copyright © 2011-2022 走看看