2013-01-23 33 views
21

Tôi có một hành động điều khiển đó là để nhận được một số nguyên và một đối tượng, có chứa các thuộc tính khác nhau, một trong số đó là một danh sách chung của các đối tượng. Khi tôi gửi JSON cho hành động với một danh sách dân cư, mọi thứ đều ánh xạ chính xác và tôi nhận được một danh sách chứa đối tượng mà tôi đã đăng. Tuy nhiên, nếu mảng trống, hành động MVC liên kết thuộc tính với một đầu vào rỗng của một danh sách rỗng. Tôi muốn mảng trống để ánh xạ tới một mảng trống và không phải là rỗng, vì mảng trống trong trường hợp này có nghĩa là không có gì trong bộ sưu tập và một hàm rỗng có nghĩa là cơ sở dữ liệu cần được kiểm tra để xem có điều gì trước đó không được lưu trong bộ sưu tập, nhưng tôi không thể tìm ra những gì tôi cần thay đổi để làm cho nó được lập bản đồ đúng cách. Chúng tôi đang sử dụng Json.Net để làm serialization đối tượng cho các đối tượng trở về, nhưng tôi không nghĩ rằng nó đang được sử dụng cho deserialization đối tượng trên mô hình ràng buộc.Json trống mảng deserializing như null trong MVC

Đối tượng được thông qua:

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 yêu cầu: "{\" id \ ": 137, \" Tiêu chí \ ": {\" ObjectsList \ ": []}}"

Điều khiển Tác vụ:

public ActionResult ProcessCriteria(int id, Criteria criteria) 
{ 
    return Json(_service.ProcessCriteria(id, criteria)); 
} 

Hành động của bộ điều khiển là tôi nhận được giá trị thay vì danh sách trống trong đối tượng tiêu chí. Nó xảy ra cho dù tôi gửi null cho các thuộc tính khác hay không. Bạn không chắc chắn nếu nó xuống đối tượng là một IList và không phải là một IEnumerable? (Các phương pháp Json gói dịch vụ gọi là wrapper của chúng tôi để trả về một kết quả json bằng cách sử dụng Json.Net để serialise phản ứng - null là trong các đối tượng tiêu chí nhận được, không phải trong các đối tượng tiêu chuẩn nhận được, không phải trong sự trở lại.)

Tôi đoán nó là một cái gì đó khá đơn giản mà tôi đang thiếu, nhưng tôi không thể làm việc ra những gì, giúp đỡ rất nhiều đánh giá cao.

+0

Dễ dàng hơn cho chúng tôi nếu bạn đặt một số mã. Một dòng mã là tốt hơn 100 từ: D –

+0

Đồng ý, tuy nhiên trong trường hợp này, tôi không chắc nó sẽ giúp ích bao nhiêu, viết tắt toàn bộ bộ điều khiển/bộ điều khiển cơ sở và các bài viết liên quan đến json của tôi. Tôi sẽ thử và đăng một cái gì đó có ý nghĩa, nhưng cho đến lúc đó, json đang hiển thị một mảng trống, và trước khi nó được đăng và khi nó được liên kết với mô hình, List là một null chứ không phải là một danh sách trống. Các bộ phận của hệ thống phân cấp điều khiển được viết bởi các dev khác, vì vậy tôi không thể nói chắc chắn, nhưng tôi không thể tìm thấy việc thực hiện ghi đè của quá trình giải mã json, vì vậy tôi nghĩ đó là xử lý mặc định của json để mô hình ràng buộc. –

+0

Kiểm tra câu hỏi này: http://stackoverflow.com/q/14203150/29555 và câu trả lời thứ hai – marto

Trả lời

0

Dưới đây là những gì tôi đăng tải dưới dạng một comment:

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

Như tôi đã nói trong bình luận ở trên, tôi muốn có thể có một trạng thái rỗng cho danh sách này, vì vậy nếu tôi thử và gửi một null trong trường hợp này, nó sẽ vẫn hiển thị nó như một danh sách trống - đó là không phải là hành vi mong muốn. –

10

ok, tôi đã phải đối mặt với vấn đề này gần 5 giờ cố gắng tìm ra giải pháp sau đó tôi thấy mình tìm trong mã nguồn MVC. và tôi thấy rằng đây là một vấn đề với mã MVC Source trong System.Web.Mvc.ValueProviderResult tại dòng 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; 
      } 
     } 

như bạn có thể thấy nếu nguồn là mảng trống rỗng, nó sẽ trả về null.

vì vậy tôi phải tìm một con đường xung quanh nó, và sau đó tôi nhớ như thế nào trong những ngày cũ tốt, chúng tôi đang làm deserialization: đây là cách bạn sẽ có được những gì bạn muốn:

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

Đây là một lỗi rõ ràng, tôi nghĩ vậy. Bạn có thể đăng sự cố hoặc thực hiện cam kết ở đó http://aspnetwebstack.codeplex.com/ –

+1

Tôi nghĩ rằng vấn đề thực tế nằm trong DefaultModelBinder https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src /System.Web.Mvc/DefaultModelBinder.cs dòng 711, nơi nó trả về null nếu 'objectList' được xây dựng không chứa gì cả. Kiểm tra điều này: https://lostechies.com/jimmybogard/2013/11/07/null-collectionsarrays-from-mvc-model-binding/ – bigbearzhu

0

Tôi có một trả lời cho bạn rằng sẽ làm việc ở cấp khung. Trong dự án của tôi, tôi đã làm việc với dữ liệu lớn hơn một chút so với các giá trị mặc định sẽ hỗ trợ. Vì vậy, tôi tạo ra ValueProviderFactory của riêng mình. Hóa ra, nếu một mảng không có mục nào trong đó, nhà cung cấp bỏ qua toàn bộ mục đó. Thay vào đó, chúng ta chỉ cần nói rằng không có mục nào trong mảng. Đây là mã bạn cần.

Đầu tiên, toàn cầu.tuyến Asax Application_Start:

public void Application_Start() 
{ 
    ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<System.Web.Mvc.JsonValueProviderFactory>().FirstOrDefault()); 
    ValueProviderFactories.Factories.Add(new LargeValueProviderFactory()); 

Thứ hai, đây là lớp khác, bạn sẽ cần:

#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

Điều này là do bạn không bao giờ xác định giá trị tính nullable trong lớp 'Tiêu chuẩn'; nếu không bao giờ xác định, nó sẽ là null.

ví dụ:

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":[]} 
    } 
    } 
Các vấn đề liên quan