为什么ASP.Net MVC模型绑定器将一个空的JSON数组绑定到null
本文关键字:绑定 一个 JSON null 数组 MVC Net ASP 模型 为什么 | 更新日期: 2023-09-27 17:58:46
这是我的模型类:
public class MyModel
{
public Employees[] MyEmpls{get;set;}
public int Id{get;set;}
public OrgName{get;set;}
}
将以下带有MyEmpls as empty array
的JSON结构对象传递给MVC控制器。
["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"]
控制器
[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
//model.MyEmpls is null here
}
我希望mode.MyEmpls
是一个空的c#数组,而不是null。是否需要自定义模型绑定器来实现空数组?
我认为其他一些答案忽略了这个问题的含义:为什么默认的MVC模型绑定器将空Json数组绑定到null,而不是空C#数组?
我不能告诉你他们为什么这么做,但我可以告诉你发生在哪里。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;
}
您可以通过在模型的构造函数中初始化数组来回避这个问题。在我对源代码的快速阅读中,我无法告诉你为什么他们不能返回空数组,或者为什么他们决定不返回,但这应该会引起有趣的阅读。
您得到的是一个null值,因为这是C#中引用类型的默认值。为了获得一个空数组,您需要使用构造函数初始化模型中的数组。然而,由于在初始化数组时需要定义数组的大小,因此最好使用另一种类型的集合,如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*/];
}
}
如果您正在获取模型。MyEmpls为null,然后您可以在服务器端创建一个条件来停止引发异常,如:
if(model.MyEmpls !=null){
...
}
您得到的是null,因为您的MyEmpls是一个自定义类数组,而您只发送[]。
希望这对你有帮助。
尝试创建如下中的模型绑定器
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
}
您可以定义一个检查值是否为空的setter
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;}
}
[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.
C#数组初始化的默认行为是空数组
因此,如果你发送一个空数组,你不会启动一个空的数组,但你会触发默认的初始化为空
请参阅以下链接http://www.dotnetperls.com/null-array