8

Using jQuery I am posting an array of int to my MVC 3 application by putting the array in the data parameter like so: data: { myIntArray: myIntArray }. In my controller, the receiving action has as a parameter int[] myIntArray.

This goes well in most cases, except when myIntArray is empty. In the request I see the following myIntArray= (note that there is no space after "="). Back in my MVC 3 controller this gets translated to an array containing one int: 0.

It doesn't seem to me like I am doing something terribly wrong here by posting an empty array. I can work around this by handling the case where the array is empty in a different way. Nevertheless, I feel that this should be possible.

Thanks in advance.

Extra info:

  • I use jQuery 1.5.1 (cannot upgrade for this project).
  • myIntArray is initialized with new Array().
Matthijs Wessels
  • 6,530
  • 8
  • 60
  • 103
  • Is `myIntArray` in javascript set to be an empty array `[]` or `undefined`? – Gabriele Petrioli Jul 20 '11 at 09:53
  • @Gaby, it is initalized like so `myIntArray = new Array()` – Matthijs Wessels Jul 20 '11 at 09:59
  • can you check with firebug and see what gets posted in the two cases (*with empty and with a filled array*) – Gabriele Petrioli Jul 20 '11 at 10:07
  • @Gaby, with values: `myIntArray=1&myIntArray=2&myInt...`. Without values `myIntArray=`. – Matthijs Wessels Jul 20 '11 at 10:21
  • In my opinion, the problem is with MVC 3 considering `myIntArray=` as an `int[] { 0 }`. I wouldn't know what else should be in the request that could indicate an empty array. – Matthijs Wessels Jul 20 '11 at 10:34
  • @Matthijs Are you sure that `myIntArray` is an array? Objects serialized as `"myIntArray="` are usually empty strings. Empty arrays are always serialized as `""`. Check if `jQuery.isArray(myIntArray)` is `true` before your post. – Paolo Moretti Jul 20 '11 at 10:43
  • @Matthijs, the issue seems to be that MVC will handle each `myIntArray` url parameter as a value of the array (*since it is a `int[] myIntArray`*). Perhaps you should avoid including the `myIntArray` url param if it empty, from the jquery side.. – Gabriele Petrioli Jul 20 '11 at 10:55
  • @Paolo, yes I'm sure, I debugged even to check if it was still an array at the moment of posting. I also posted `data: { myIntArray: new Array() }`: same result. `Empty arrays are always serialized as ""`, the value of it is serialized as `""`. But as I said, I wouldn't know what else to expect to be honest. – Matthijs Wessels Jul 20 '11 at 10:55
  • @Gaby, that's what I am doing now. This results in `int[] myIntArray` being `null` on the MVC side. I do a check if it is `null` and then initialize it with an empty array. But this is a really a hack. – Matthijs Wessels Jul 20 '11 at 10:57
  • @Matthijs `jQuery.ajax({ type: "POST", url: "...", data: { intMyArray: [] }, });` (at least the latest version 1.6.2 with FF 5.0) perform an HTTP POST request with no parameters, so I can't figure out why how you can get this `myIntArray=`. Which version of jQuery are you using? – Paolo Moretti Jul 20 '11 at 11:10
  • 1
    @Matthijs You are right, I'm getting the same problem with 1.5.1. So one solution could be to switch to latest version (1.6.2). – Paolo Moretti Jul 20 '11 at 11:33
  • @Paolo, ok, thanks for the response. I don't think we can switch to the latest jQuery now anymore though in this project (almost completed). I'll just keep my workaround, add some comments to it and check the rest of the project if anything has this problem. Also I will bring this to the attention to the rest of the team for the future. – Matthijs Wessels Jul 20 '11 at 11:40

2 Answers2

6

You could do this:

var myIntArray = new Array();

// add elements or leave empty
myIntArray.push(1);
myIntArray.push(5);

var data = myIntArray.length > 0 ? { myIntArray: myIntArray } : null;

$.ajax({
    url: '@Url.Action("someAction")',
    type: 'POST',
    data: data,
    traditional: true,
    success: function (result) {
        console.log(result);
    }
});

or use a JSON request:

var myIntArray = new Array();
// add elements or leave empty
myIntArray.push(1);
myIntArray.push(5);

$.ajax({
    url: '@Url.Action("someAction")',
    type: 'POST',
    data: JSON.stringify(myIntArray),
    contentType: 'application/json',
    success: function (result) {
        console.log(result);
    }
});
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    what does `traditional = 'true'` specify – Muhammad Adeel Zahid Jul 20 '11 at 12:12
  • both these ajax requests would send json data wouldn't they? if so why Json.stringyfy – Muhammad Adeel Zahid Jul 20 '11 at 12:13
  • @Muhammad Adeel Zahid, the [`traditional`](http://api.jquery.com/jQuery.param) parameter specifies the desired serialization style so that it plays well with the default model binder. The first request sends `application/x-www-form-urlencoded` whereas the second sends a JSON request. – Darin Dimitrov Jul 20 '11 at 13:25
  • Your first suggestion is about what I do now. However, don't those both result in the array being `null` in the MVC 3 action? I would like to just receive an empty array. – Matthijs Wessels Jul 20 '11 at 13:38
  • @Matthijs Wessels, yes both result into receiving `null` on the controller action if the array is empty on the client side. As far as receiving empty arrays is concerned, the default model binder doesn't support this but you could write your own custom model binder for the `int[]` type and achieve this functionality if you needed. – Darin Dimitrov Jul 20 '11 at 13:41
0

Just in case anyone lands on this question trying to resolve this...

This is a bug in MVC (that still exists in MVC 4 in 2019, duh):

  • when you POST an empty form parameter into an action method that has an array-mapped variable or model - this results in an 1-element zero array { 0 }.

I found no other way than to deal with it on the back-end.

Here's another question discussing it: ASP.NET MVC Int Array parameter with empty array defaults to {0}

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149