将JSON数组发布到MVC控制器

18

我想向MVC控制器发布一个JSON数组。但是无论我尝试什么,所有内容都为0或null。

我有一个包含文本框的表格。我需要从所有这些文本框中获取它们的ID和值作为对象。

这是我的Javascript:

$(document).ready(function () {

    $('#submitTest').click(function (e) {

        var $form = $('form');
        var trans = new Array();

        var parameters = {
            TransIDs: $("#TransID").val(),
            ItemIDs: $("#ItemID").val(),
            TypeIDs: $("#TypeID").val(),
        };
        trans.push(parameters);


        if ($form.valid()) {
            $.ajax(
                {
                    url: $form.attr('action'),
                    type: $form.attr('method'),
                    data: JSON.stringify(parameters),
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    success: function (result) {
                        $('#result').text(result.redirectTo)
                        if (result.Success == true) {
                            return fase;
                        }
                        else {
                            $('#Error').html(result.Html);
                        }
                    },
                    error: function (request) { alert(request.statusText) }
                });
        }
        e.preventDefault();
        return false;
    });
});

这是我的视图代码:
<table>
        <tr>
            <th>trans</th>
            <th>Item</th>
            <th>Type</th>
        </tr>

        @foreach (var t in Model.Types.ToList())
        {
            {
            <tr>
                <td>                  
                    <input type="hidden" value="@t.TransID" id="TransID" />
                    <input type="hidden" value="@t.ItemID" id="ItemID" />
                    <input type="hidden" value="@t.TypeID" id="TypeID" />
                </td>
            </tr>
           }
        }
</table>

这是我试图接收数据的控制器:

[HttpPost]
public ActionResult Update(CustomTypeModel ctm)
{


   return RedirectToAction("Index");
}

我做错了什么?

1
请展示一下你的 CustomTypeModel 是什么样子。 - Darin Dimitrov
你正在使用哪个版本的 MVC? - Peter Rasmussen
看起来你可能缺少正在尝试POST的属性名称的name属性。你能发布实际的数据和POST请求吗? - rae1
@DarinDimitrov,你在回答中部分正确地理解了CustomTypeModel。我忘记发布那段代码了。但是你提到的那些部分是最重要的。 - Yustme
3个回答

60

你的代码存在许多问题。首先从标记开始说起。你有一个表格,在每一行中都包含了隐藏字段。但是,你硬编码了这些隐藏元素的id属性,这意味着你可能最终会在你的标记中拥有多个具有相同id的元素,导致无效的标记。

因此,我们首先需要修复你的标记:

@foreach (var t in Model.Types.ToList())
{
    <tr>
        <td>                  
            <input type="hidden" value="@t.TransID" name="TransID" />
            <input type="hidden" value="@t.ItemID" name="ItemID" />
            <input type="hidden" value="@t.TypeID" name="TypeID" />
        </td>
    </tr>
}

好的,现在您有有效的标记。接下来让我们转向javascript事件,当某个submitTest按钮被点击时将触发该事件。如果这是表单的提交按钮,我建议您订阅表单的.submit事件,而不是其提交按钮的.click事件。原因是,例如,如果用户在某个输入字段中按下Enter键,则可能会提交表单。在这种情况下,您的click事件将不会被触发。
$(document).ready(function () {
    $('form').submit(function () {
        // code to follow

        return false;
    });
});

好的,接下来需要收集表格内隐藏元素的值,并将它们放入一个JavaScript对象中,然后我们将对该对象进行JSON序列化,并将其作为AJAX请求的一部分发送到服务器。

我们来继续吧:

var parameters = [];
// TODO: maybe you want to assign an unique id to your table element
$('table tr').each(function() {
    var td = $('td', this);
    parameters.push({
        transId: $('input[name="TransID"]', td).val(),
        itemId: $('input[name="ItemID"]', td).val(),
        typeId: $('input[name="TypeID"]', td).val()
    });
});

到目前为止,我们已经填好了参数,现在让我们将它们发送到服务器:

$.ajax({
    url: this.action,
    type: this.method,
    data: JSON.stringify(parameters),
    contentType: 'application/json; charset=utf-8',
    success: function (result) {
        // ...
    },
    error: function (request) { 
        // ...
    }
});

现在我们来到了服务器端。像往常一样,我们首先定义一个视图模型:
public class MyViewModel
{
    public string TransID { get; set; }
    public string ItemID { get; set; }
    public string TypeID { get; set; }
}

并且需要编写一个控制器动作,接收此模型的集合:

[HttpPost]
public ActionResult Update(IList<MyViewModel> model)
{
    ...
}

这是最终的客户端代码:

$(function() {
    $('form').submit(function () {
        if ($(this).valid()) {
            var parameters = [];
            // TODO: maybe you want to assign an unique id to your table element
            $('table tr').each(function() {
                var td = $('td', this);
                parameters.push({
                    transId: $('input[name="TransID"]', td).val(),
                    itemId: $('input[name="ItemID"]', td).val(),
                    typeId: $('input[name="TypeID"]', td).val()
                });
            });

            $.ajax({
                url: this.action,
                type: this.method,
                data: JSON.stringify(parameters),
                contentType: 'application/json; charset=utf-8',
                success: function (result) {
                    // ...
                },
                error: function (request) { 
                    // ...
                }
            });
        }
        return false;
    });
});

显然,如果您的视图模型不同(您在问题中没有展示它),您可能需要调整代码以使其匹配您的结构,否则默认的模型绑定器将无法反序列化JSON。


当我遇到类似的问题时,我的 C# 模型类缺少每个属性的 { get; set; } - BillDarcy

7

还有另一种更简单的方法:使用查询字符串来发送数据。如果您感兴趣,您当前的方法是错误的,因为JSON数组数据类型是string而不是CustomTypeModel

首先,删除data ajax选项。我们不再需要它。

其次,更改您的控制器如下:

[HttpPost]
public ActionResult Update(string json)
{
    // this line convert the json to a list of your type, exactly what you want.
    IList<CustomTypeModel> ctm = 
         new JavaScriptSerializer().Deserialize<IList<CustomTypeModel>>(json);

    return RedirectToAction("Index");
}

注意1:您的CustomTypeModel属性名称与您输入的JSON元素相同非常重要。因此,您的CustomTypeModel应该像这样:
public class CustomTypeModel
{
    // int, or maybe string ... whatever you want.
    public int TransIDs { get; set; }
    public int ItemIDs { get; set; }
    public int TypeIDs { get; set; }
}

注意2:当您想要通过查询字符串发送数据时,这种方法非常有用。因此,您的URL可以像这样:
url: '/controller/action?json=' + JSON.stringify(trans)

-1

我认为你在MVC世界中的做法有些不对。

如果你有一个适当的模型来绑定数据,最好使用内置的帮助程序而不是使用“手工制作”的JavaScript。如果需要异步调用,请查看HtmlHelper或AjaxHelper。

并在@Html.BeginForm块内使用@Html.TextBoxFor()符号将数据绑定到模型。这将简化您的代码并减少JavaScript的数量,这对于维护来说更好。

在服务器端,您需要实现自定义模型绑定器并更改设置以通过您的模型绑定器处理当前控制器操作的请求。这将需要编写一些服务器端代码,但静态类型的代码对我来说更容易编写和测试,并且更适合您的应用程序需求,因为我更喜欢JavaScript执行它应该执行的任务= >管理UI,而不是构建模型以便在服务器端正确解析。这更适合单一职责原则。

请参见video,这是一个简单的教程。


这是一个复杂类型。无法像那样绑定,至少我还没有想出如何做到。JavaScript现在对我有效。但是值得一提的是,没有@Html.InputFor()。 - Yustme
谢谢关于InputFor的提醒,我上次在编写Java时很难正确记住所有名称。我已经编辑了我的答案,你可以看一下。 - Ph0en1x
听起来很不错,但我已经尝试了很多方法来避免使用JavaScript。这是一个复杂的模型。此外,我确实使用了@Html.TextBoxFor(),但我不知道如何使用JavaScript获取其中的数据。 - Yustme
2
该函数的第二个参数是一个简单的POCO对象,其中包含HTML属性及其值。您可以编写类似于@Html.TextBoxFor(m => m.SomeValue, new {id="myControl"})的代码,然后通过类似于普通输入框的ID从JavaScript中查询它。 - Ph0en1x
啊,我不知道可以这样做。这样做使代码更易读,谢谢! - Yustme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接