【问题标题】:AJAX is failing to pass array to controllerAJAX 无法将数组传递给控制器
【发布时间】:2020-08-05 17:49:49
【问题描述】:

您好,我有一个执行此操作的 AJAX 函数

     $("button").click(function () {
                //var token = $("input[name='__RequestVerificationToken']", "#__AjaxAntiForgeryForm").val();
                var partArray = []; //for creating json array
                //looping through trs with class tr_clonePart
                $(".tr_clonePart").each(function () {
                    //for storing qtys and radios of cloned and original
                    var qty_actiontype_cloned = []
                    var datas_cloned = {};
                    var data_original = {}//fro original
                    var qty_actiontype_original = [];
                    //get infos for various fields
                    var p_id = $(this).find("td > a").attr('p-id');
                    var mfg = $(this).find("input.part_mfg").val();
                    var part_name = $(this).find("input.part_name").val();
                    var qty_in_item = $(this).find("input.qty_in_item").val();
                    var item = {};
                    //add values in json objects
                    item["PartID"] = p_id
                    item["MFGNumber"] = mfg
                    item["PartName"] = part_name
                    item["QtyInItem"] = qty_in_item
                    //chcking if part-class is checked or not
                    if ($(this).find("input[type='checkbox'].part-class").is(':checked')) {

                        var move_all = $(this).find("input[type='checkbox'].part-class").val();
                       // item["MoveAll"] = move_all
                        item["MoveAll"] = (move_all == "true");
                        var radios = $(this).find("input[type='radio'].radios:checked").val();
                        data_original["action_type"] = radios //adding value of radios in array
                        //item['radios_c'] = radios_c
                        var qty = $(this).find("input.qty").val();
                        data_original["qty"] = qty //adding value of qty in array
                        qty_actiontype_original.push(data_original)
                        item["QtyActionTypeOriginal"] = qty_actiontype_original
                        //item["qty"] = qtys
                    } else {
                        var qty = $(this).find("input.qty").val();
                        //for original data
                        data_original["qty"] = qty
                        var radios = $(this).find("input[type='radio'].radios:checked").val();
                        //for original data
                        data_original["action_type"] = radios
                        qty_actiontype_original.push(data_original)
                        item["QtyActionTypeOriginal"] = qty_actiontype_original
                        //item["MoveAll"] = "false"
                        item["MoveAll"] = (move_all == "false");
                        //looping through cloned trs
                        $(".tr_clonePart_" + p_id).each(function () {

                            var radios_clones = $(this).find("input[type='radio'].radios:checked").val();
                            //puuting value in cloned array
                            datas_cloned["action_type"] = radios_clones

                            console.log(radios_clones)
                            var qty_clones = $(this).find("input.qty").val();

                            datas_cloned["qty"] = qty_clones
                            //push data in cloned array
                            qty_actiontype_cloned.push(datas_cloned)

                        });
                        //push array in cloned json object
                        item["QtyActionTypeCloned"] = qty_actiontype_cloned


                    }
                    //getting other values
                    var OnHand = $(this).find("input.OnHand").val();
                    var onWorkOrder = $(this).find("input.onWorkOrder").val();
                    var committed = $(this).find("input.committed").val();
                    var fstk = $(this).find("input.fstk").val();
                    item["OnHand"] = OnHand
                    item["OnWorkOrder"] = onWorkOrder
                    item["Committed"] = committed
                    item["FSTK"] = fstk
                    //push json object in array
                    partArray.push(item)

                })
                console.log(partArray)

                //allParts = JSON.stringify(partArray);
                @*model = JSON.stringify(@Model);*@
                $.ajax({
                    type: "POST",
                    url: "@IGT.baseUrl/JODetails/SpecialOrderSelection",
                     contentType: "application/json; charset=utf-8",
                    data:
                        JSON.stringify({ allParts: partArray }),
                        @*JSON.stringify(@Model),*@


                    dataType: "json",
                    traditional: true,
                    success: function () {
                        alert('Success!');
                    },
                    error: function () {
                        alert('Error! ');
                    }
                });
                event.preventDefault()

            })

控制台日志给了我这些数据

所以我希望将数组传递给我的控制器,

这就是我的 Controller 方法的设置方式

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult SpecialOrderSelection(ItemViewModel model, ItemPartViewModel[] allParts)
        {
       
            if (ModelState.IsValid)
            {
                JobOrder jobOrder = db.JobOrders.Find(model.Id);
                if (jobOrder == null)
                {
                    return HttpNotFound();
                }
                ViewBag.JobOrderID = jobOrder.ID;
                TempData["model"] = model;
                return RedirectToAction("SpecialOrderSummary", new { id = model.Id });
            }
            
            return View(model);
            
        }

但 allParts 总是返回 NULL。

这里是 itemPartViewModel 类的设置方式


public class QtyActionTypeCloned
    {
        public string action_type { get; set; }
        public string qty { get; set; }
    }

    public class QtyActionTypeOriginal
    {
        public string action_type { get; set; }
        public string qty { get; set; }
    }


public class ItemPartViewModel
    {
        [Required]
        public int ID { get; set; }
        public int ItemID { get; set; }
        public string PartID { get; set; }
        public string MFGNumber { get; set; }
        public string PartName { get; set; }
        public float QtyInItem { get; set; }
        public float Qty { get; set; }
        public bool MoveAll { get; set; }
        public float OnHand { get; set; }
        public float OnWorkOrder { get; set; }
        public float Committed { get; set; }
        public float FSTK { get; set; }

        public QtyActionTypeCloned qty_actiontype_cloned { get; set; }
        public QtyActionTypeOriginal qty_actiontype_original { get; set; }

        // This is the additional property to contain what user picks
        public PartActionType SelectedActionType { get; set; }
    }

这是我的数组有效负载

这是我渲染的 html

  <tbody>
<input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="Parts_0__ID" name="Parts[0].ID" type="hidden" value="346" /><input id="Parts_0__PartID" name="Parts[0].PartID" type="hidden" value="600601" /><input data-val="true" data-val-number="The field ItemID must be a number." data-val-required="The ItemID field is required." id="Parts_0__ItemID" name="Parts[0].ItemID" type="hidden" value="117" />                            <tr class="tr_clonePart">

                                <td>
                                    <a p-id=346 style='color:#FF00FF;' href='#'>600601</a>
                                </td>
                                <td>
                                    S-16706, Uline
                                    <input id="Parts_0__MFGNumber" name="Parts[0].MFGNumber" type="hidden" value="S-16706, Uline" />
                                </td>
                                <td>
                                    Supply - Packing Carton, 9&quot; x 8&quot; x 8&quot;, MU/AX
                                    <input id="Parts_0__PartName" name="Parts[0].PartName" type="hidden" value="Supply - Packing Carton, 9&quot; x 8&quot; x 8&quot;, MU/AX" />
                                </td>
                                <td style="font-weight:bold">
                                    <span class="qtyInItem">
                                        1
                                        <input data-val="true" data-val-number="The field QtyInItem must be a number." data-val-required="The QtyInItem field is required." id="Parts_0__QtyInItem" name="Parts[0].QtyInItem" type="hidden" value="1" />
                                    </span>

                                </td>
                                <td>
                                    <input checked="checked" class="part-class" data-partId="346" data-val="true" data-val-required="The MoveAll field is required." id="Parts_0__MoveAll" name="Parts[0].MoveAll" type="checkbox" value="true" /><input name="Parts[0].MoveAll" type="hidden" value="false" />
                                </td>

                                <td>
                                    <div class="AllTxt">
                                        1
                                    </div>
                                    <div class="editQty">
                                        <input class="qty text-box single-line" data-val="true" data-val-number="The field Qty must be a number." data-val-required="The Qty field is required." id="Parts_0__Qty" name="Parts[0].Qty" type="text" value="0" />
                                    </div>
                                </td>
                                <td>
                                    <span class="onHand">
                                        202
                                        <input data-val="true" data-val-number="The field OnHand must be a number." data-val-required="The OnHand field is required." id="Parts_0__OnHand" name="Parts[0].OnHand" type="hidden" value="202" />
                                    </span>
                                </td>
                                <td>
                                    <span class="onWorkOrder">
                                        0
                                        <input data-val="true" data-val-number="The field OnWorkOrder must be a number." data-val-required="The OnWorkOrder field is required." id="Parts_0__OnWorkOrder" name="Parts[0].OnWorkOrder" type="hidden" value="0" />
                                    </span>
                                </td>
                                <td>
                                    <span class="committed">
                                        76
                                        <input data-val="true" data-val-number="The field Committed must be a number." data-val-required="The Committed field is required." id="Parts_0__Committed" name="Parts[0].Committed" type="hidden" value="76" />
                                    </span>

                                <td>
                                    <span class="fstk">
                                        126
                                        <input data-val="true" data-val-number="The field FSTK must be a number." data-val-required="The FSTK field is required." id="Parts_0__FSTK" name="Parts[0].FSTK" type="hidden" value="126" />
                                    </span>
                                </td>


                                    <td>
                                        <input checked="checked" class="radios" data-val="true" data-val-required="The SelectedActionType field is required." id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Transfer" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Harvest" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Dispose" />
                                    </td>
                            </tr>
<input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="Parts_1__ID" name="Parts[1].ID" type="hidden" value="106" /><input id="Parts_1__PartID" name="Parts[1].PartID" type="hidden" value="700504" /><input data-val="true" data-val-number="The field ItemID must be a number." data-val-required="The ItemID field is required." id="Parts_1__ItemID" name="Parts[1].ItemID" type="hidden" value="117" />                            <tr class="tr_clonePart">

                                <td>
                                    <a p-id=106 style='color:#FF00FF;' href='#'>700504</a>
                                </td>
                                <td>
                                    725M10, SuperBonder
                                    <input id="Parts_1__MFGNumber" name="Parts[1].MFGNumber" type="hidden" value="725M10, SuperBonder" />
                                </td>
                                <td>
                                    Supply - Glue Stick 0.28&quot; x 10&quot;
                                    <input id="Parts_1__PartName" name="Parts[1].PartName" type="hidden" value="Supply - Glue Stick 0.28&quot; x 10&quot;" />
                                </td>
                                <td style="font-weight:bold">
                                    <span class="qtyInItem">
                                        0.125
                                        <input data-val="true" data-val-number="The field QtyInItem must be a number." data-val-required="The QtyInItem field is required." id="Parts_1__QtyInItem" name="Parts[1].QtyInItem" type="hidden" value="0.125" />
                                    </span>

                                </td>
                                <td>
                                    <input checked="checked" class="part-class" data-partId="106" data-val="true" data-val-required="The MoveAll field is required." id="Parts_1__MoveAll" name="Parts[1].MoveAll" type="checkbox" value="true" /><input name="Parts[1].MoveAll" type="hidden" value="false" />
                                </td>

                                <td>
                                    <div class="AllTxt">
                                        0.125
                                    </div>
                                    <div class="editQty">
                                        <input class="qty text-box single-line" data-val="true" data-val-number="The field Qty must be a number." data-val-required="The Qty field is required." id="Parts_1__Qty" name="Parts[1].Qty" type="text" value="0" />
                                    </div>
                                </td>
                                <td>
                                    <span class="onHand">
                                        265.5402
                                        <input data-val="true" data-val-number="The field OnHand must be a number." data-val-required="The OnHand field is required." id="Parts_1__OnHand" name="Parts[1].OnHand" type="hidden" value="265.5402" />
                                    </span>
                                </td>
                                <td>
                                    <span class="onWorkOrder">
                                        0
                                        <input data-val="true" data-val-number="The field OnWorkOrder must be a number." data-val-required="The OnWorkOrder field is required." id="Parts_1__OnWorkOrder" name="Parts[1].OnWorkOrder" type="hidden" value="0" />
                                    </span>
                                </td>
                                <td>
                                    <span class="committed">
                                        31.368
                                        <input data-val="true" data-val-number="The field Committed must be a number." data-val-required="The Committed field is required." id="Parts_1__Committed" name="Parts[1].Committed" type="hidden" value="31.368" />
                                    </span>

                                <td>
                                    <span class="fstk">
                                        234.1722
                                        <input data-val="true" data-val-number="The field FSTK must be a number." data-val-required="The FSTK field is required." id="Parts_1__FSTK" name="Parts[1].FSTK" type="hidden" value="234.1722" />
                                    </span>
                                </td>


                                    <td>
                                        <input checked="checked" class="radios" data-val="true" data-val-required="The SelectedActionType field is required." id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Transfer" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Harvest" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Dispose" />
                                    </td>
                            </tr>

谁能帮助确定为什么我的数组返回 NULL 的问题?

【问题讨论】:

  • 我很困惑,您的控制器操作接受 ItemViewModel 和数组。但是在您的 jQuery 中,您只发布数组。这是为什么呢?
  • 它已经发布了 itemviewmodel,所以我没有将它添加到我的 AJAX 帖子 @DaveBarnett
  • 对不起,我还是一头雾水。发布 ItemViewModel 的内容是什么?
  • 我不确定发布 itemViewModel 的内容。我在想它只是默认发送 itemViewModel @DaveBarnett
  • 似乎遇到了 AJAX,出现错误,然后运行 ​​POST @DaveBarnett

标签: javascript c# jquery ajax asp.net-mvc


【解决方案1】:

问题至少部分是客户端上的属性名称与服务器上的属性名称不匹配。例如,在客户端上有 move_all,在服务器上有 MoveAll。为了使模型绑定起作用,这些需要相同。另一个问题是数据类型也不匹配。在客户端 move_all 是一个字符串,而在服务器上 MoveAll 是一个布尔值。在不知道您的客户端代码如何获取数据的情况下,很难为此推荐修复程序。我认为您可以采取两种方法。一种是在用于绑定数据的服务器上创建一种桥接视图模型。然后,您可以将数据从桥接视图模型复制到您想要的数据,即ItemPartViewModel 的数组。您可以采取的另一种方法是将客户端上的数组映射到与您的ItemPartViewModel 匹配的另一个对象数组。

客户端方法可以通过例如改变来实现

item["p_id"] = p_id;

item["PartId"] = parseInt(p_id);

对于布尔值,这将起作用

item["MoveAll"] = (move_all == "true");

现在属性和类型与 c# viewModel 匹配。您需要对所有属性执行类似操作,以便它们都匹配。

这是一些工作代码的演示,希望对您有所帮助

查看模型和控制器

public class RawQtyActionTypeCloned
{
    public string action_type { get; set; }
    public string qty { get; set; }
}


public class RawItemPartViewModel
{
    public string move_all { get; set; }
    public string p_id { get; set; }

    public RawQtyActionTypeCloned qty_actiontype_cloned { get; set; }

}

public class JODetailsController : Controller
{
    public ActionResult SpecialOrderSelection()
    {
        return View();
    }

    [HttpPost]
    public ActionResult SpecialOrderSelection(RawItemPartViewModel[] allParts)
    {
        return Content(allParts.Length.ToString());
    }
}

景色

<button id="myButton">
    Click me
</button>

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<script>

    var array = [{
        move_all: "false",
        p_id: "346",
        qty_actiontype_cloned: [{
            action_type: "Dispose",
            qty: "1"
        }]
    }, {
        move_all: "true",
        p_id: "106",
        qty_actiontype_cloned: [{
            action_type: "Dispose",
            qty: "2"
        }]
    },
    {
        move_all: "true",
        p_id: "341",
        qty_actiontype_cloned: [{
            action_type: "Dispose",
            qty: "3"
        }]
    }
    ];

    $(document).ready(function () {
        var myButton = document.getElementById("myButton");
        myButton.addEventListener('click', onMyButtonClicked);



        function onMyButtonClicked(e) {
            e.preventDefault();

                 $.ajax({
                    type: "POST",
                     url: "/JODetails/SpecialOrderSelection",
                    contentType: "application/json; charset=utf-8",
                    data: JSON.stringify({ allParts: array }),
                    dataType: "json",
                    traditional: true
                });
        }

    });
</script>

注意我的属性名称和类型是如何匹配的。

这是我在查看帖子时在开发者工具的网络选项卡中看到的屏幕截图。

编辑:在您的ItemPartViewModel 更改中

 public QtyActionTypeOriginal QtyActionTypeOriginal { get; set; }

  public QtyActionTypeOriginal[] QtyActionTypeOriginal { get; set; }

因为在客户端它是一个数组。

【讨论】:

  • 好的,谢谢,我会尝试这样做并让您知道结果。我是否需要在我的视图模型类中添加 qty_actiontype_original 和 qty_actiontype_cloned 作为数组?
  • 是的,把它们放进去。你可以随时尝试移​​除它们,看看它是否可以在没有的情况下工作。
  • 嗯,即使在实施更改后,我也会返回 null。我已更新我的问题以反映我所做的更改
  • 当您点击帖子时,我已经添加了来自网络选项卡的请求负载的屏幕截图。您能否为您的问题制作类似的屏幕截图并将其添加到您的问题中?
  • 我认为这是因为我忘记将 moveAll 更改为布尔值。如何更改我的 javascript 使其成为布尔值?
【解决方案2】:

因为您的属性之一需要[ValidateAntiForgeryToken],所以您将获得空值。它实际上会触发500 (Internal Server Error),因为它会在继续控制器方法之前寻找那个令牌。

一个建议是删除您的[ValidateAntiForgeryToken],一切都会正常。我试过你的代码,没有它也能正常工作。

如果你想要[ValidateAntiForgeryToken]。我建议你用这个修改你的代码:

   //Add the AntiForgeryToken on the your Post data:
   var token = $(':input[name="__RequestVerificationToken"]').val();
   $.ajax({
       type: "POST",
       url: "@IGT.baseUrl/JODetails/SpecialOrderSelection",
       //contentType: "application/json; charset=utf-8", --Remove this one
       //data: JSON.stringify({ allParts: array }), --Change this to new object below
       data: {
           '__RequestVerificationToken': token,
           'allParts': JSON.stringify(array)
       },
       dataType: "json",
       traditional: true                 
    });

然后在您的控制器上,反序列化您传递的数据:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SpecialOrderSelection(FormCollection data)
    {
      var results = JsonConvert.DeserializeObject<List<ItemPartViewModel>>(data["allParts"]);
    }

如果你传递allParts作为参数,你仍然会得到null,所以只需在FormCollection上获取它并获取键值对,然后对其进行反序列化。

【讨论】:

  • 是的,我刚刚注意到这一点并正在修复它。谢谢!
  • 但只是一个关于你有var results = JsonConvert.DeserializeObject&lt;List&lt;App&gt;&gt;(data["allParts"]);的发布方法的问题我在App收到一个错误
  • 啊,我明白了。谢谢!
  • 嗯,我在控制器方法中收到“值不能为空。参数名称:值”的错误
  • 确保模型中的所有属性都相同。我注意到 MoveAll 不等于您的 javascript 对象上的 move_all。
猜你喜欢
  • 1970-01-01
  • 2015-09-18
  • 2017-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多