Почему механизм связывания модели ASP.Net MVC связывает пустой массив JSON со значением NULL?
Вот мой класс модели:
public class MyModel
{
public Employees[] MyEmpls{get;set;}
public int Id{get;set;}
public OrgName{get;set;}
}
Передача объекта структуры JSON ниже с MyEmpls as empty array
в контроллер MVC.
["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"]
контроллер
[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
//model.MyEmpls is null here
}
Я ожидаю, что mode.MyEmpls
будет пустым массивом С#, а не null. Нужно ли связывать пользовательские модели для получения пустого массива?
Ответы
Ответ 1
Я думаю, что некоторые из других ответов упустили смысл вопроса: почему привязка модели MVC по умолчанию связывает пустой массив Json с нулевым, а не пустым массивом С#?
Хорошо, я не могу сказать вам, почему они это сделали, но я могу показать вам, где это происходит. Источник для MVC можно найти на CodePlex здесь: http://aspnetwebstack.codeplex.com/SourceControl/latest. Файл, который вы ищете, ValueProviderResult.cs, где вы можете видеть:
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);
}
}
Интересной частью является "случай 3":
else
{
// case 3(a): source is empty array, so can't perform conversion
return null;
}
Вы можете обойти эту проблему, инициализируя свой массив в модели в своем конструкторе. В моем быстром чтении источника я не могу сказать вам, почему они не могут вернуть пустой массив или почему они не решили, но это должно сделать интересное чтение.
Ответ 2
Вы получаете нулевое значение, так как это значение по умолчанию для ссылочного типа в С#. Чтобы получить пустой массив, вам нужно будет инициализировать массив в вашей модели с помощью конструктора. Однако, поскольку вам нужно будет определить размер массива при его инициализации, возможно, лучше использовать другой тип коллекции, такой как 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>();
}
}
Затем вы получите пустой список, когда пустой пул передается из json.
Если вам действительно нужно использовать массив, просто инициализируйте его размером:
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];
}
}
Ответ 3
Если вы получаете model.MyEmpls как null, тогда вы можете создать условие на стороне сервера, чтобы остановить повышение исключений, например:
if(model.MyEmpls !=null){
...
}
И вы получаете его null, потому что MyEmpls - это массив пользовательского класса, и вы отправляете только [].
Надеюсь, это поможет вам.
Ответ 4
Попробуйте создать привязку к модели, как показано ниже
public class MyModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
try
{
var request = controllerContext.HttpContext.Request;
return new MyModel
{
MyEmpls = request[] ?? new Employees[0],
Id = request["Id"] ?? "",
OrgName = request["OrgName"] ?? ""
};
}
catch
{
//do required exception handling
}
}
}
В регистре Application_Start привязка к модели
ModelBinders.Binders.Add(typeof(MyModel), new MyModelBinder())
И измените контроллер как
[HttpPost]
public ActionResult SaveOrg([ModelBinder(typeof(MyModelBinder))] MyModel model)
{
//model.MyEmpls is null here
}
Ответ 5
[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
var serializer = new JavaScriptSerializer();
var stream = System.Web.HttpContext.Current.Request.InputStream;
var reader = new StreamReader(stream);
stream.Position = 0;
var json = reader.ReadToEnd();
model= serializer.Deserialize<MyModel>(json);
//model.MyEmpls is [] here
}
JavaScriptSerializer корректно десериализует пустые массивы. Таким образом, вы можете игнорировать переданную модель и перестроить ее из потока запросов ввода. Наверное, не правильный путь, но если вам нужно сделать это только после того, как это сэкономит какое-то усилие. Вам нужно будет ссылаться на System.Web.Extensions.
Ответ 6
Поведение по умолчанию для инициализации массива С# - это пустой пустой массив
Итак, если вы отправляете пустой массив, вы не будете запускать пустой массив, но вы инициируете инициализацию по умолчанию null
См. следующую ссылку
http://www.dotnetperls.com/null-array
Ответ 7
вы можете определить сеттер, который проверяет, имеет ли значение значение null
public class MyModel
{
private _myEmpls{get;set;}
public Employees[] MyEmpls{
get{return _myEmpls;}
set{_myEmpls=(value==null?new List<Employees>():value);}
}
public int Id{get;set;}
public OrgName{get;set;}
}