【问题标题】:Posting serialized form data AND additional data to MVC controller?将序列化的表单数据和其他数据发布到 MVC 控制器?
【发布时间】:2014-03-13 01:06:23
【问题描述】:

我正在尝试在发送到我的服务器的 POST 请求中添加一些额外的数据。最初,我只发送了几种形式的信息:

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    data: $('form').serialize(),
    dataType: 'json'
});

和MVC控制器方法:

[HttpPost]
public ActionResult SaveAllDetails([Bind(Prefix = "order")]ExistingOrderDetailsModel existingOrderDetailsModel, 
    [Bind(Prefix = "task")]ExistingTaskDetailsModel existingTaskDetailsModel, [Bind(Prefix = "device")]DeviceDetailsModel deviceDetailsModel)
{
    ....
}

这很好用。 MVC 的模型绑定器能够正确反序列化 URL 编码的字符串。

现在,要求发生了变化。我需要连同我的三个表格一起发送一个额外的数据数组。此数据数组不保存在表单中,也没有绑定前缀。我需要在同一个 Controller 方法中完成这一切,因为所有验证都需要在单个事务中执行。

所以,我现在得到了:

var subcomponentsGridRows = JSON.stringify(subcomponentsDetailsView.getAllGridData());
var existingOrderDetailsFormData = $('form#existingOrderDetailsForm').serialize();
var existingTaskDetailsFormData = $('form#existingTaskDetailsForm').serialize();
var deviceDetailsFormData = $('form#existingDeviceDetailsForm').serialize()

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    data: {
        existingOrderDetailsModel: existingOrderDetailsFormData,
        existingTaskDetailsModel: existingTaskDetailsFormData,
        deviceDetailsModel: deviceDetailsFormData,
        subcomponentsGridRows: subcomponentsGridRows
    },
    dataType: 'json'
});

这不起作用至少有一个原因。每个表单都表示为 URL 编码的字符串。 subcomponentsGridRows 是一个 JSON 结构。据我所知,MVC 模型绑定器无法一次性破译这两种类型的信息。

解决这个问题的好方法是什么?

【问题讨论】:

  • subcomponentsGridRows is a JSON structure and the MVC model binder isn't capable of deciphering that mess。为何如此?如果你创建了一个代表这个结构的模型(比如说,使用这个网站:json2csharp.com),那么模型绑定器会很高兴地绑定到它。
  • 您可以在提交之前合并数据或在 POST url 中使用 GET 传递其他信息...
  • @SimonWhitehead 当我将数据发布到服务器时,我必须指出我发送的信息类型。表单是 URL 编码的实体。网格数据是 JSON 结构。 MVC 会很乐意接受其中一个,但据我所知,没有一种简单的方法可以将两者结合到一个请求中。
  • @dandavis 但我将如何合并两者?一种是 URL 编码的字符串,另一种是 JSON 结构。我看了这个答案:stackoverflow.com/questions/17038396/… 但数据仍然没有通过。
  • 把url字符串变成一个对象,然后合并。 js 库和 .net 提供 queryString 解析器。

标签: c# javascript asp.net-mvc


【解决方案1】:

您可能会发现following plugin 很有用。

以下是它可能对您有用的方式。让我们通过定义一个视图模型来清理你的控制器动作:

public class MyViewModel
{
    public ExistingOrderDetailsModel Order { get; set; }
    public ExistingTaskDetailsModel Task  { get; set; }
    public DeviceDetailsModel Device  { get; set; }

    public AdditionalRowsViewModel[] AdditionalRows { get; set; }
}

在此示例中,AdditionalRowsViewModel 显然会保存您尝试传递给控制器​​操作的附加信息。

然后你的控制器动作会变成:

[HttpPost]
public ActionResult SaveAllDetails(MyViewModel model)
{
    ....
}

好的,这一步是绝对必要的,只是当我看到一个控制器动作需要超过 1 个参数时,我只是定义了一个视图模型。

最后让我们调整我们的 AJAX 调用:

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({
        order: $('form#existingOrderDetailsForm').serializeObject(),
        task: $('form#existingTaskDetailsForm').serializeObject(),
        device: $('form#existingDeviceDetailsForm').serializeObject(),
        additionalRows: subcomponentsDetailsView.getAllGridData()
    }),
    success: function(result) {
        // do something with the result of the AJAX call here
    }
});

注意事项:

  1. 在您的 AJAX 请求中去掉这个 dataType: 'json' 参数。您正在使用 ASP.NET MVC,希望您从控制器操作返回 Jsonresult,该操作成功地将 Content-Type 响应标头设置为正确的值。 jQuery 足够智能,可以使用此响应标头的值并预处理 result 变量,该变量将传递给 AJAX 请求的 success 回调。所以在这种情况下,你已经得到了一个 javascript 对象
  2. 由于您在 AJAX 请求中将 JSON 发送到服务器,因此您需要正确指定 contentType: application/json 参数。否则,您如何期望 ASP.NET MVC 知道客户端正在发送 JSON 并应用正确的模型绑定器?顺便说一句,jQuery 将发送的默认 Content-Type 请求标头是 application/x-www-form-urlencoded,因此如果您在 POST 请求中发送 JSON 有效负载,这将是冲突和违反协议的。

【讨论】:

  • 您的解决方案如何考虑表单前缀?我无法将单个前缀绑定到 MyViewModel 的每个属性。据我所知,前缀必须与单个参数或整个类相关联。我是否应该修改 serializeObject 以去除“订单”、“任务”。和“设备”。键的前缀?
  • 如果属性名称是唯一的,那么您确实可以修改插件以将它们考虑在内并删除它们。或者,您可以更新它以生成复杂的 JSON 子对象。
  • 每个对象的属性名称是唯一的,但在表单之间是不唯一的。我认为这对于解决方案来说是可以的,因为一旦每个表单都被隔离到一个给定的对象中,它就没有歧义了。当我有我的最终解决方案时,我会更新,但谢谢你这似乎是正确的方法。干杯。
  • 什么是 .serializeObject() ?
  • @SeanAnderson 我通过为我的表单使用部分视图解决了前缀问题。不确定这是否是最佳做法,但它有效
猜你喜欢
  • 2022-01-22
  • 2015-01-31
  • 1970-01-01
  • 1970-01-01
  • 2019-09-08
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
  • 2015-02-14
相关资源
最近更新 更多