Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the ASP.Net MVC model binder bind an empty JSON array to null?

Here is my model class:

public class MyModel {     public Employees[] MyEmpls{get;set;}     public int Id{get;set;}     public OrgName{get;set;} } 

Passing the below JSON structure object with MyEmpls as empty array to MVC controller.

["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"] 

Controller

[HttpPost] public ActionResult SaveOrg(MyModel model) {   //model.MyEmpls is null here } 

I am expecting mode.MyEmpls to be an empty c# array, not a null. Is a custom model binder necessary to achieve an empty array?

like image 904
Billa Avatar asked Apr 16 '14 11:04

Billa


People also ask

What is JSON binding in ASP.NET MVC?

if we send any json object from JavaScript to asp.net mvc controller action method json object can directly bind to strongly typed . net object (model or viewmodel in asp.net mvc) automatically, provider will take care validations, serializing, de-serializing values etc.

How does model binding works in MVC?

Model binding is a well-designed bridge between the HTTP request and the C# action methods. It makes it easy for developers to work with data on forms (views), because POST and GET is automatically transferred into a data model you specify. ASP.NET MVC uses default binders to complete this behind the scene.

Does MVC use data binding?

MVC doesn't use data bindings like old web api. You have to use model bindings in a MVC or MVVM approach.

What is model binding in asp net core MVC?

Model binding allows controller actions to work directly with model types (passed in as method arguments), rather than HTTP requests. Mapping between incoming request data and application models is handled by model binders.


2 Answers

I think that some of the other answers have missed the meaning of the question: why does the default MVC model binder bind an empty Json array to null instead of an empty C# array?

Well, I can't tell you why they did that, but I can show you where it happens. The source for MVC can be found on CodePlex here: http://aspnetwebstack.codeplex.com/SourceControl/latest. The file you're looking for is ValueProviderResult.cs where you can see:

    private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType)     {         if (value == null || destinationType.IsInstanceOfType(value))         {             return value;         }          // array conversion results in four cases, as below         Array valueAsArray = value as Array;         if (destinationType.IsArray)         {             Type destinationElementType = destinationType.GetElementType();             if (valueAsArray != null)             {                 // case 1: both destination + source type are arrays, so convert each element                 IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);                 for (int i = 0; i < valueAsArray.Length; i++)                 {                     converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);                 }                 return converted;             }             else             {                 // case 2: destination type is array but source is single element, so wrap element in array + convert                 object element = ConvertSimpleType(culture, value, destinationElementType);                 IList converted = Array.CreateInstance(destinationElementType, 1);                 converted[0] = element;                 return converted;             }         }         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;             }         }         // case 4: both destination + source type are single elements, so convert         return ConvertSimpleType(culture, value, destinationType);     } } 

The interesting part is "case 3":

else {     // case 3(a): source is empty array, so can't perform conversion     return null; } 

You can sidestep this issue by initialising your array on the model in its constructor. In my quick reading of the source I can't tell you why they can't return an empty array or why they decide not to, but it should make for interesting reading.

like image 75
Richiban Avatar answered Sep 18 '22 13:09

Richiban


You're getting a null value as this is the default value for a reference type in C#. In order to get an empty array you will need to initialise the array in your model using a constructor. However as you will need to define the size of the array when it's initialized it might be better using another type of collection such as a List:

public class MyModel {     public List<Employees> MyEmpls{get;set;}     public int Id{get;set;}     public OrgName{get;set;}      public MyModel()      {          MyEmpls = new List<Employees>();     } } 

You will then get an empty list when an empty array is passed from the json.

If you really have to use an array just initialise it with a size:

public class MyModel {     public Employees[] MyEmpls{get;set;}     public int Id{get;set;}     public OrgName{get;set;}      public MyModel()      {          MyEmpls = new Employees[/*enter size of array in here*/];     } } 
like image 36
James Avatar answered Sep 20 '22 13:09

James