Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json empty array deserializing as null in MVC

Tags:

I have a controller action which is to receive an integer and an object, containing various properties, one of which is a generic list of objects. When I post JSON to the action with a populated list, everything maps correctly and I get a list containing the object that I have posted. If the array is empty however, the MVC action binds the property to a null intead of an empty list. I want the empty array to map to an empty array and not to a null, as the empty array in this case means that there is nothing in the collection, and a null means that the database should be checked to see if there is anything previously saved in the collection, but I can't figure out what I need to change to get it to map properly. We are using Json.Net to do object serialization for returning objects, but I don't think it's being used for object deserialization on model binding.

Objects being passed:

public class ObjectInList {     public decimal Value1 { get; set; }     public decimal Value2 { get; set; } }  public class Criteria {     public decimal? ANullableNumber { get; set; }     public IList<ObjectInList> ObjectsList { get; set; } } 

Json request: "{\"id\":137,\"criteria\":{\"ObjectsList\":[]}}"

Controller Action:

public ActionResult ProcessCriteria(int id, Criteria criteria) {     return Json(_service.ProcessCriteria(id, criteria)); } 

It is in the controller action that I am getting a null instead of an empty list in the criteria object. It happens whether I send nulls for the other properties or not. Not sure if it's down to the object being an IList and not an IEnumerable? (The Json method wrapping the service call is our wrapper to return a json result using Json.Net to serialise the response - the null is in the criteria object received, not in the return.)

I'm guessing it's something pretty simple that I'm missing, but I can't work out what, any help greatly appreciated.

like image 657
Ian Cotterill Avatar asked Jan 23 '13 11:01

Ian Cotterill


People also ask

Can a JSON array be null?

JSON has a special value called null which can be set on any type of data including arrays, objects, number and boolean types.

Can you pass null in JSON?

Passing a null value to any Corticon Server using JSON payloads is accomplished by either: Omitting the JSON attribute inside the JSON object. Including the attribute name in the JSON Object with a value of JSONObject.

What does null mean in JSON?

null is not zero. It is not a value, per se: it is a value outside the domain of the variable indicating missing or unknown data. There is only one way to represent null in JSON.


2 Answers

ok, i was facing this issue almost 5 hours trying find the solution then i found myself looking in the MVC source code. and i found that this is a problem with the Mvc Source code in System.Web.Mvc.ValueProviderResult at Line 173:

        else if (valueAsArray != null)         {             // case 3: destination type is single element but source is array, so                     extract first element + convert             if (valueAsArray.Length > 0)             {                 value = valueAsArray.GetValue(0);                 return ConvertSimpleType(culture, value, destinationType);             }             else             {                 // case 3(a): source is empty array, so can't perform conversion                 return null;             }         } 

as you can see if source is empty array it will return null.

so i have to find a way around it, and then i remember how in the good old days we was doing deserialization: this is how you will get what you want:

    public ActionResult ProcessCriteria(int id, Criteria criteria)     {         var ser = new System.Web.Script.Serialization.JavaScriptSerializer();         StreamReader reader = new StreamReader(System.Web.HttpContext.Current.Request.InputStream);         reader.BaseStream.Position = 0;         criteria = ser.Deserialize<Criteria>(reader.ReadToEnd());          return Json(_service.ProcessCriteria(id, criteria));     } 
like image 126
ygaradon Avatar answered Sep 28 '22 04:09

ygaradon


One way of resolving this issue is assigning a new instance as a default value for your ObjectsList like this:

public class Criteria {     public decimal? ANullableNumber { get; set; }     public IList<ObjectInList> ObjectsList { get; set; } = new List<ObjectInList>(); } 

This will create an empty List instead of null if there's no values in your JSON array.

like image 44
krlzlx Avatar answered Sep 28 '22 02:09

krlzlx