我有一个控制器动作,它接收一个整数和一个对象,包含各种属性,其中一个是对象的通用列表。当我使用填充列表将JSON发布到操作时,一切都正确映射,我得到一个包含我发布的对象的列表。但是,如果数组为空,则MVC操作会将该属性绑定到空列表的null intead。我希望空数组映射到空数组而不是空数,因为在这种情况下空数组意味着集合中没有任何内容,而null意味着应该检查数据库以查看以前是否有任何内容保存在集合中,但我无法弄清楚我需要更改以使其正确映射。我们使用Json.Net为返回对象执行对象序列化,但我认为它不会用于模型绑定上的对象反序列化。
传递的对象:
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请求: “{\” ID \ “:137,\” 标准\ “:{\” ObjectsList \ “:[]}}”
控制器操作:
public ActionResult ProcessCriteria(int id, Criteria criteria)
{
return Json(_service.ProcessCriteria(id, criteria));
}
我在控制器操作中获取null而不是条件对象中的空列表。无论我是否为其他属性发送空值,都会发生这种情况。不确定它是否属于IList而不是IEnumerable? (包装服务调用的Json方法是我们的包装器,它使用Json.Net返回一个json结果来序列化响应 - null在收到的条件对象中,而不是在返回中。)
我猜这是一件非常简单的事情,我很遗憾,但我无法解决这个问题,任何帮助都非常感激。
答案 0 :(得分:11)
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;
}
}
你可以看到source是否为空数组,它将返回null。
所以我必须找到解决方法,然后我记得在过去的好时光中我们正在进行反序列化: 这就是你将得到你想要的东西:
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));
}
答案 1 :(得分:0)
以下是我发布的评论:
public class Criteria
{
public decimal? ANullableNumber { get; set; }
private IList<ObjectInList> _objectsList = new List<ObjectInList>();
public IList<ObjectInList> ObjectsList
{
get { return _objectsList; }
set {
if(value != null)
_objectsList = value;
}
}
}
答案 2 :(得分:0)
我有一个可以在框架级别工作的答案。在我的项目中,我使用的数据比默认值支持的数据要大一些。因此,我创建了自己的ValueProviderFactory。事实证明,如果数组中没有项目,则提供程序会完全跳过该条目。相反,我们只需告诉它数组中没有任何项目。这是您需要的代码。
首先,global.asax Application_Start:
public void Application_Start()
{
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<System.Web.Mvc.JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new LargeValueProviderFactory());
其次,这是您需要的其他课程:
#region << Usings >>
using System;
using System.Collections.Generic;
using System.Collections;
using System.Web.Mvc;
using System.IO;
using System.Web.Script.Serialization;
using System.Globalization;
#endregion
/// <summary>
/// This class is to ensure we can receive large JSON data from the client because the default is a bit too small.
/// </summary>
/// <remarks>This class is from the web.</remarks>
public sealed class LargeValueProviderFactory : System.Web.Mvc.ValueProviderFactory
{
#region << Constructors >>
/// <summary>
/// Default constructor.
/// </summary>
public LargeValueProviderFactory()
: base()
{
// Nothing to do
}
#endregion
#region << GetValueProvider >>
public override System.Web.Mvc.IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
#endregion
#region << Helper Methods >>
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
if (l.Count == 0)
backingStore[prefix] = value;
return;
}
// primitive
backingStore[prefix] = value;
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = Int32.MaxValue;
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
#endregion
}
答案 3 :(得分:0)
我认为实际问题出在DefaultModelBinder.cs第711行,如果构建的objectList
不包含任何内容,则返回null。看看这个:https://lostechies.com/jimmybogard/2013/11/07/null-collectionsarrays-from-mvc-model-binding/
答案 4 :(得分:0)
解决此问题的一种方法是像这样为ObjectsList
分配一个新实例作为默认值:
public class Criteria
{
public decimal? ANullableNumber { get; set; }
public IList<ObjectInList> ObjectsList { get; set; } = new List<ObjectInList>();
}
如果您的JSON数组中没有值,这将创建一个空的List
而不是null
。
答案 5 :(得分:-2)
这是因为你永远不会在'Criteria'类中定义可为空的属性值;如果从未定义,它将为null。
例如:
public class Criteria {
public decimal? ANullableNumber { get; set; }
public IList<ObjectInList> ObjectsList { get; set; }
}
public class Criteria1 {
private IList<ObjectInList> _ls;
private decimal? _num;
public decimal? ANullableNumber {
get {
if (_num == null) return 0;
return _num;
}
set {
_num = value;
}
}
public IList<ObjectInList> ObjectsList {
get {
if (_ls == null) _ls = new List<ObjectInList>();
return _ls;
}
set {
_ls = value;
}
}
}
public class HomeController : Controller {
public ActionResult Index() {
var dd = new Criteria();
return Json(dd); //output: {"ANullableNumber":null,"ObjectsList":null}
}
public ActionResult Index1() {
var dd = new Criteria1();
return Json(dd); //output: {"ANullableNumber":0,"ObjectsList":[]}
}
}