【问题标题】:Jquery Post to ASP.NET API ControllerJquery 发布到 ASP.NET API 控制器
【发布时间】:2014-12-17 23:19:15
【问题描述】:

我有一个通过 jquery 生成的表单:

 $.get("/api/get/getListItems", function (data) {
                var table = "";
                table += "<table>";
                $.each(data, function (y, z) {
                    console.log(z);
                    table += '<tr>';
                    $.each(this, function (k, v) {
                        table += '<td><input type="text" name="' + k + '" id="' + k + '" value="' + v + '" /></td>';
                    });
                    table += '<td><input type="checkbox" name="selected" id="selected" /></td>';

                    table += '</tr>';
                });
                table += '<tr><td><input type="submit" id="submit" name="submit" value="Save To Database" /></td></tr>';
                table += '</table>';
                $('#form').html(table);
            });

它会生成这个 HTML(10 行输入字段、7 列和 1 个复选框):http://jsfiddle.net/8zpr2fkL/1/

点击提交按钮时我正在提交表单:

$("#form").submit(function (event) {
        $.post("/api/update/", $("#form").serialize(), alert('success'));
    });

现在我将数据传递给我的 ASP.NET API 控制器:

[HttpPost]
        public dynamic Post([FromBody]CellModel cells)
        {
                UpdateClass jobs = new UpdateClass();
                return jobs;
        }

这是我的 CellModel 类:

public class CellModel
    {
        public uint scheduleTaskID { get; set; }
        public string task { get; set; }
        public string baselineDate { get; set; }
        public string scheduledDate { get; set; }
        public string actualDate { get; set; }
        public string finishedDate { get; set; }
        public bool selected { get; set; }

        public override string ToString()
        {
            return scheduleTaskID.ToString();
        }
    }

我的问题是当我点击提交以提交数据并在控制器方法上设置断点时,单元格计数为 0,我在这里缺少什么吗?我正在尝试将输入文本中的所有数据传递给控制器​​。没有任何东西传递给我的控制器。我做错了什么?

这是我试图通过 jquery $('#form').serialize() 传递的数据:

scheduleTaskID=194&task=Permit&baselineDate=6%2F23%2F2005+8%3A00%3A00+AM&scheduledDate=6%2F23%2F2005+8%3A00%3A00+AM&actualDate=6%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=195&task=Office+Files&baselineDate=7%2F13%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F13%2F2005+8%3A00%3A00+AM&actualDate=7%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=196&task=Foundation&baselineDate=7%2F27%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F27%2F2005+8%3A00%3A00+AM&actualDate=8%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=197&task=Framing&baselineDate=8%2F5%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F5%2F2005+8%3A00%3A00+AM&actualDate=8%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=198&task=Finishes+Exterior&baselineDate=8%2F26%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F26%2F2005+8%3A00%3A00+AM&actualDate=9%2F14%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=199&task=Drywall&baselineDate=9%2F2%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F2%2F2005+8%3A00%3A00+AM&actualDate=9%2F16%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=200&task=Flooring&baselineDate=9%2F1%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F1%2F2005+8%3A00%3A00+AM&actualDate=9%2F20%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=201&task=General+Finish&baselineDate=9%2F12%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F12%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=202&task=Final+PDI&baselineDate=10%2F11%2F2005+8%3A00%3A00+AM&scheduledDate=10%2F11%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=203&task=Permit&baselineDate=4%2F6%2F2005+8%3A00%3A00+AM&scheduledDate=4%2F6%2F2005+8%3A00%3A00+AM&actualDate=4%2F6%2F2005+8%3A00%3A00+AM&finishedDate=

更新

我变了:

$("#form").submit(function (event) {
            $.post("/api/update/", $("#form").serialize(), alert('success'));
        });

$("#form").submit(function (event) {
        var array = [];
        $('#form > table > tbody  > tr').each(function (elem) {
            var item = {};
            item.scheduleTaskID = $(this).find("td > #scheduleTaskID").val();
            item.task = $(this).find("td > #task").val();
            item.baselineDate = $(this).find("td > #baselineDate").val();
            item.scheduledDate = $(this).find("td > #scheduledDate").val();
            item.actualDate = $(this).find("td > #actualDate").val();
            item.finishedDate = $(this).find("td > #finishedDate").val();
            item.selected = $(this).find("td > #selected").val();
            array.push(item);
        });
        console.log(JSON.stringify(array));
        $.post("/api/update/", JSON.stringify(array), alert('success'), 'json');
    });

在我的控制台日志中,我的数据如下所示:

[{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"195","task":"Office Files","baselineDate":"7/13/2005 8:00:00 AM","scheduledDate":"7/13/2005 8:00:00 AM","actualDate":"7/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"196","task":"Foundation","baselineDate":"7/27/2005 8:00:00 AM","scheduledDate":"7/27/2005 8:00:00 AM","actualDate":"8/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"197","task":"Framing","baselineDate":"8/5/2005 8:00:00 AM","scheduledDate":"8/5/2005 8:00:00 AM","actualDate":"8/23/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"198","task":"Finishes Exterior","baselineDate":"8/26/2005 8:00:00 AM","scheduledDate":"8/26/2005 8:00:00 AM","actualDate":"9/14/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"199","task":"Drywall","baselineDate":"9/2/2005 8:00:00 AM","scheduledDate":"9/2/2005 8:00:00 AM","actualDate":"9/16/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"200","task":"Flooring","baselineDate":"9/1/2005 8:00:00 AM","scheduledDate":"9/1/2005 8:00:00 AM","actualDate":"9/20/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"201","task":"General Finish","baselineDate":"9/12/2005 8:00:00 AM","scheduledDate":"9/12/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"202","task":"Final PDI","baselineDate":"10/11/2005 8:00:00 AM","scheduledDate":"10/11/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{}]

在我的 ASP.NET API 控制器中,我将方法更改为:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
    public class UpdateController : ApiController
    {
        [HttpPost]
        public dynamic Post(List<CellModel> cells)
        {
                UpdateClass jobs = new UpdateClass();
                //jobs.PostScheduledTasks(cells);
                return cells;
        }

    }
}

我在 Post 方法的开头放置了一个断点,当它到达断点时,它显示单元格 Count = 0 ..我看到网络调用,只有当我在 post 调用之后返回 false 并且响应为空时[]为什么数据没有传给我的控制器,是不是因为表单是jquery生成的?

更新

仍然没有解决办法,我查看了我的网络调用这个 AM 并且状态码是 301:

【问题讨论】:

  • 不应该是 CellModel 的列表吗?看起来您发回的不止 1 个...这可能无法解决问题,但值得一看...
  • 是的,我要发送不止一个....
  • 另一件事要尝试。你有没有从你的帖子中取出[FromBody]?另外,这些数据是从 Fiddler 之类的东西生成的吗?这是通过网络传递的内容吗?
  • 如果您从 Chrome 中执行此操作,您可以使用检查器、网络选项卡并准确查看回传到控制器的内容。我还将断点放在 Post 行之后,以确保在中断之前填充单元格。
  • 另外,我用它来测试我的控制器/REST API:chrome.google.com/webstore/detail/dev-http-client/…

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


【解决方案1】:

不要使用 $.post 使用 ajax post 并将内容类型设置为 "应用程序/json; charset=utf-8"

var data = JSON.stringify(array);
$.ajax({
  url:"/api/update/",
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(data){
    console.log(data);
  }
});

问题是你需要告诉网络服务器你正在发送 json,而 $.post 是不可能的

这真的很正常,我也一直在努力解决这个问题(有时我还是忘记了),在这里你可以看到你必须使用 $.ajax

Jquery - How to make $.post() use contentType=application/json?

【讨论】:

  • @user979331 它可以工作,但它的时空性能比使用 $.post 的解决方案更差(查看我的答案)。您在 foreach 循环中将表单元素转换为 JSON,并使用 jQuery 进行重复的 DOM 搜索,这是完全没有必要的。如果您遵循下面列出的规则,只需序列化表单并发布就会简单得多。
  • @TheZenCoder,不知道你的方法,很好,但我在阅读了所有链接后发现客户端性能的损失是可鄙的。 (老实说)我可能没有使用过巨大的表格,我不知道其他任何表格,但是您可以创建的平均表格没有损失。无论如何,我认为你的方法是积极的。周末愉快:D
  • @dariogriffo,是的,也许这不是一个巨大的性能差异,但是序列化()表单和 $.post 的代码更简单,因为您不必处理 JSON。无论如何,您的方法也很有效,并且被广泛接受。知道同一问题的多种解决方案总是很好的;)感谢您的支持!
【解决方案2】:

我知道,这已经使用.ajax 而不是.post 解决了。我想分享这个,因为我已经使用.post 解决了这个问题。如上所述,由于它的内容类型为Content-Type:application/x-www-form-urlencoded; charset=UTF-8,因此post方法中的参数cells将包含count = 0

要解决这个问题,您必须手动捕获请求对象并获取发布数据,然后反序列化并获取对象为List&lt;CellModel&gt;。我已经使用了 OP 发布的所有代码,并且只是修改了post 方法,如下所示,它起作用了。

[HttpPost]
public dynamic Post(List<CellModel> cells)
{
    string content = string.Empty;
    if (HttpContext.Current.Request.InputStream.CanSeek)
    {
        HttpContext.Current.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
    }
    using (System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Current.Request.InputStream))
    {
        content = reader.ReadToEnd();
    }
    if (!string.IsNullOrEmpty(content))
    {
        // Deserialize and operate over cells.
        try
        {
            var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(content, typeof(List<CellModel>));
        }
        catch (Exception ex)
        {
            return ex;
        }

    }
    return cells;
}

这是我在调试时得到的。

【讨论】:

  • 假设您的 API 中有 120 个 POST 端点,这是完全不可维护的
  • 我不知道,OP 的用例是什么,如果您知道,请告诉我,我刚刚尝试使用.post 解决,这是可行的。但是是的,.ajax 是处理 webapi 中使用的HTTPPost 的最佳方式。
【解决方案3】:

虽然您通过 @dariogriffo 获得了另一种方法,但我想使用 $.post 的初始方法为您提供完整的解决方案。

您最初使用表单序列化的方法是正确的,因此以下代码是正确的:

$("#form").submit(function (event) {
   $.post("/api/update/", $("#form").serialize(), alert('success'));
});

但是,这不起作用,因为 您的动态表单没有遵循 ASP.NET MVC 默认模型绑定器所期望的输入字段的命名约定,因此您的序列化表单没有默认模型绑定器能够绑定到您的cells 模型。这就是为什么您在执行 POST 时没有在控制器中获取任何单元格的原因。

为了阐明这意味着什么,如果您要发布到常规 MVC 5 控制器,ASP.NET 期望与模型属性对应的每个输入字段具有以下名称格式:

actionattributename[index].propertyname

如果您要发布到 Web API 2 控制器,它应该是:

[index].propertyname

由于您的操作属性被命名为 cells 并且它具有属性 scheduledTaskID,并且您正在发布到 WebAPI 控制器,因此您的输入之一如下所示:

<input type="text" name="[0].scheduleTaskID" id="scheduleTaskID" value="194">

在构建表单以使其可绑定时,还涉及更多规则。你可以在这里找到一篇不错的博客文章:

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

如果您遵循该表单约定,您将能够将您的序列化表单发布到您的控制器,期待 List&lt;CellModel&gt; cells 无需使用 JSON 方法,这要贵得多,如其他答案。

下面是一个由 Web API 2 默认绑定规则正确构造的示例表单:

http://jsfiddle.net/8zpr2fkL/12/

您可以尝试使用 $.post 将此表单 $.post 到您的 Web api 控制器,它应该像一个魅力一样工作!

【讨论】:

  • 我也喜欢这个解决方案
猜你喜欢
  • 2013-12-15
  • 2014-12-19
  • 2021-08-08
  • 2020-01-10
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多