2013-01-23 26 views
21

我有一個控制器動作,它接收一個整數和一個對象,其中包含各種屬性,其中之一是對象的通用列表。當我將JSON發佈到帶有填充列表的操作時,所有內容都正確映射,並且我得到一個包含我發佈的對象的列表。如果該數組爲空,則MVC操作將該屬性綁定到空列表的空intead。我想讓空數組映射到一個空數組而不是空數組,因爲在這種情況下,空數組意味着集合中沒有任何內容,並且null表示應該檢查數據庫以查看以前是否有任何內容保存在集合中,但我無法弄清楚我需要更改以使其正確映射。我們使用Json.Net來爲返回對象做對象序列化,但我不認爲它被用於模型綁定上的對象反序列化。被傳遞Json空數組反序列化爲MVC中的空值

對象:

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)); 
} 

正是在這我得到一個空值而不是空列表中的標準對象的控制作用。是否發送其他屬性的空值會發生。不確定它是否屬於IList而不是IEnumerable? (包裝服務調用的Json方法是我們的​​包裝,它使用Json.Net返回一個json結果來對響應進行序列化 - null在收到的標準對象中,而不是在返回中。)

我猜這是某種東西很簡單,我錯過了,但我無法解決什麼,任何幫助非常感謝。

+0

如果你放一些代碼對我們來說更容易。一行代碼優於100個單詞:D –

+0

同意,但是在這種情況下,我不確定它會提供多大幫助,但是沒有發佈我的整個控制器/基本控制器和相關的json帖子。我會嘗試發佈一些有意義的東西,但在此之前,json顯示一個空數組,並且在它被髮布之前以及綁定到模型之前,List是一個空而不是空列表。控制器層次結構的一部分是由其他開發人員編寫的,所以我不能肯定地說,但我找不到json反序列化的重載實現,所以我認爲這是json模型綁定的默認處理。 –

+0

檢查這個問題:http://stackoverflow.com/q/14203150/29555和第二個答案 – marto

回答

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; 
     } 
    } 
} 
+1

正如我在上面的評論中所說的,我希望能夠對這個列表也有一個空狀態,所以如果我在這種情況下嘗試發送一個null,它仍然會顯示它爲一個空列表 - 這是不是理想的行爲。 –

10

好吧,我面臨這個問題,近5小時,試圖找到解決 後來我發現自己看在MVC的源代碼。 ,我發現,這是對MVC的源代碼的問題System.Web.Mvc.ValueProviderResult 在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; 
      } 
     } 

,你可以看到,如果來源是空的數組會返回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

這是一個明顯的錯誤,我想。 你可以發佈問題或提交在那裏http://aspnetwebstack.codeplex.com/ –

+1

我會認爲實際的問題是在DefaultModelBinder https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src /System.Web.Mvc/DefaultModelBinder.cs第711行,如果構建的'objectList'不包含任何內容,則返回null。看看這個:https://lostechies.com/jimmybogard/2013/11/07/null-collectionsarrays-from-mvc-model-binding/ – bigbearzhu

0

我有一個爲您的答案,將在框架級別工作。在我的項目中,我正在處理比默認值支持的數據更大的數據。因此,我創建了我自己的ValueProviderFactory。事實證明,如果數組中沒有項目,則提供程序完全跳過該條目。相反,我們只需告訴它陣列中沒有項目。這是您需要的代碼。

首先,全球。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 

} 
-2

這是因爲你從來沒有定義「標準」類爲空的屬性值;如果從未定義,它將爲空。

例如:

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":[]} 
    } 
    }