通过AJAX将数组传递给MVC Action

129
我正试图通过 AJAX 将 int 数组(或 IEnumerable)传递到 MVC 操作中,需要一些帮助。
JavaScript 代码如下:
$.get('/controller/MyAction', { vals: arrayOfValues }, function (data) {...

控制器的操作是

public ActionResult MyAction(IEnumerable<int> arrayOfValues )

目前请求的格式为:

controller/MyAction?_=1301503418429&arrayOfValues[]=491&arrayOfValues[]=368&arrayOfValues[]=235&arrayOfValues[]=437

我已经接近成功了,如果我去掉方括号,我可以得到正确的响应。我应该如何将该数组传递到我的get中,以便控制器能够识别它?

非常感谢您的帮助

Dave

12个回答

152

在进行get调用之前将traditional属性设置为true。

jQuery.ajaxSettings.traditional = true

$.get('/controller/MyAction', { vals: arrayOfValues }, function (data) {... 

3
谢谢!您能否概述传统Ajax和非传统Ajax之间的区别?我想更好地了解我对应用程序的其余部分做了什么。 - Tom Beech
5
您可以将传统设置添加到单个呼叫中。这样就不会影响其他部分。 - Gluip
1
这个答案是正确的,但如果您更喜欢在单个调用中设置“传统”,请查看@RionWilliams的答案。投票支持两者。谢谢! - kzfabi
自 jQuery 1.4 起,$.param() 方法递归地序列化深层对象以适应现代脚本语言和框架,如 PHP 和 Ruby on Rails。您可以通过设置 jQuery.ajaxSettings.traditional = true 来全局禁用此功能。@Tom Beech - Alexey Shevelyov
1
没事了,我找到答案了。这与深度序列化无关。PHP最初接受数组的方式是这样的:"arrayOfValues=1&arrayOfValues=2"。新的编码方式是这样的:"arrayOfValues[]=1&arrayOfValues[]=2"。第二种方式更好,因为它不那么模糊。非常失望.NET MVC没有解析第二种方式。 - Jason Cheng
显示剩余2条评论

127

过去我在尝试进行POST时遇到了问题(不确定你是否也在做这个),但我记得当传递一个数组时,需要将 traditional 设置为true。

 var arrayOfValues = new Array();

 //Populate arrayOfValues 
 $.ajax({ 
      type: "POST",
      url: "<%= Url.Action("MyAction","Controller")%>",
      traditional: true,
      data: { 'arrayOfValues': arrayOfValues }              
 });

4
这比有些人提出的在 web.config 文件中全局设置要好得多,后者虽然也有其适用的场合,但你的方法应该成为默认解决方案。 - Panzercrisis
这只是将数据作为参数发送到ActionResult,它会调用ActionResult内部的代码吗?例如,如果有一些将arrayofvalues插入数据库的代码,那么该代码会运行吗? - Saurabh
这正好解决了我的问题。在我添加了这个之前,我的控制器中的数组一直返回为空,现在我可以像这样在控制器中获取它们:IEnumerable<string> array。 - SeanMC

56

相对于已经存在的答案,这是一个相当晚但不同的回答:

如果您想使用简写函数$.get$.post,而不是$.ajax,您可以以这种方式传递数组:


简写GET

var array = [1, 2, 3, 4, 5];
$.get('/controller/MyAction', $.param({ data: array }, true), function(data) {});


// Action Method
public void MyAction(List<int> data)
{
    // do stuff here
}

简写POST


var array = [1, 2, 3, 4, 5];
$.post('/controller/MyAction', $.param({ data: array }, true), function(data) {});


// Action Method
[HttpPost]
public void MyAction(List<int> data)
{
    // do stuff here
}


注意:

  • $.param 中的布尔参数是用于 traditional 属性的,必须将其设置为 true 才能正常工作

2
谢谢你提供关于传统属性的提示。我之前无法理解为什么我的C#参数为空。我发现在C# Action方法中,类型“int []”也可以使用。 - Dan Randolph
这应该是被接受的答案。我想指出 - 在ajax调用中,他使用了"data".... 这必须与您操作中的参数名称匹配。我首先尝试使用"data"和不同的名称,终点仍然被触发,但数据为null。 - BrianLegg
@BrianLegg 是的,必须这样做,因为 { data: array } 是一个 JavaScript 对象,它会被转换成 JSON 字符串,然后在 .NET 端进行解构,赋值给具有相同名称的变量。所以如果你的 C# API 方法有像 (string name, int age) 这样的参数,那么你在 $.param 中的 JavaScript 对象就必须与之匹配,例如 { name: "John", age: 40 } - SNag

9
您应该可以轻松完成此操作:
$.ajax({
   url: 'controller/myaction',
   data: JSON.stringify({
      myKey: myArray
   }),
   success: function(data) { /* Whatever */ }
});

那么您的动作方法应该如下所示:
public ActionResult(List<int> myKey)
{
    // Do Stuff
}

对于您来说,看起来您只需要将值转换为字符串。MVC中的JSONValueProvider将把它转换回IEnumerable。


谢谢你的回答,但我认为我需要将传统设置为true。我已经点赞了,因为我认为这也可以起作用。 - Dave

9
使用“传统”选项的答案是正确的。我只是为那些希望了解更多的人提供一些背景信息。
从jQuery文档中可以得知:
自jQuery 1.8以来,$.param()方法不再使用jQuery.ajaxSettings.traditional作为其默认设置,并且默认为false。
您还可以在以下链接中阅读更多: http://michaelsync.net/2012/04/05/tips-asp-net-mvc-javascriptserializer-3-questions-and-3-answershttp://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx 希望对你有所帮助。

4

来晚了,但我可以在$.ajax()中使用SNag的解决方案。如果有帮助,这里是代码:

var array = [1, 2, 3, 4, 5];

$.ajax({
    type: "GET",
    url: '/controller/MyAction',
    data: $.param({ data: array}, true),
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
    },
    error: function (x, y, z) {
    }
});

// Action Method
public void MyAction(List<int> data)
{
    // do stuff here
}

2

如果一切都失败了...

这里的其他答案都没有解决我的问题。我试图从JavaScript调用一个MVC Web API控制器的GET方法,并在该请求中发送一个整数数组作为参数。我尝试了这里的所有解决方案,但是我的控制器上的参数仍然为空(或者对于VB用户来说是Nothing)。

最终我在不同的SO帖子中找到了我的解决方案,而且它实际上非常简单:只需在控制器中的数组参数之前添加[FromUri]注释(我还必须使用“传统”的AJAX设置进行调用以避免括号注释)。请参见下面我在应用程序中使用的实际代码。


控制器签名:

Controller Signature 注意:C#中的注释将是 [FromUri]


JavaScript:

$.get('/api/InventoryApi/GetBalanceField', $.param({productIds: [42], inventoryFormId: 5493, inventoryBalanceType: 'Beginning'},true)).done(function(data) {console.log(data);});

实际的URL字符串:

http://randomhostname/api/InventoryApi/GetBalanceField?productIds=42&inventoryFormId=5493&inventoryBalanceType=Beginning

2
如果你像我一样从.Net Framework MVC迁移到ASP.NET Core MVC,那么有些东西会略有变化。Ajax调用必须在原始对象上使用stringify,因此不再传递{ vals: arrayOfValues }数据,而应该按照以下方式传递:JSON.stringify(arrayOfValues)。"Original Answer"翻译成“最初的回答”。
$.ajax({
   url: 'controller/myaction',
   data: JSON.stringify(arrayOfValues),
   success: function(data) { /* Whatever */ }
});

在ASP.NET Core中进行的另一个更改是为了防止跨站请求伪造,因此对于从ajax方法调用MVC操作的情况,必须将[FromBody]属性应用于操作参数,如下所示:"最初的回答"。
public ActionResult MyAction([FromBody] IEnumerable<int> arrayOfValues )

谢谢,这真的非常有帮助!在其他所有发送数据的方式都失败后,这个方法终于成功了! - NibblyPig

0
如果您需要传递更多参数,其中par1是一个数组,则JSON必须包含每个参数,我使用了以下代码:

$.ajax({
type: "POST",
url: URL,                    
data: JSON.stringify({ par1: val1, par2: val2 }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {},
error: function (result) {}
});

0

如果你正在使用ASP.NET Core MVC,并且需要处理方括号(而不是使用jQuery的“传统”选项),我找到的唯一选择是在控制器方法中手动构建IEnumerable

string arrayKey = "p[]=";
var pArray = HttpContext.Request.QueryString.Value
    .Split('&')
    .Where(s => s.Contains(arrayKey))
    .Select(s => s.Substring(arrayKey.Length));

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