开发者

Deserialize JSON with embedded Dictionary<string, string>

开发者 https://www.devze.com 2023-01-14 19:32 出处:网络
I need to determine if the DataContractJsonSerializer can deserialize JSON to a Dictionary if the Dictionary is not the wrapping object being deserialized. I know there are other open source codes pro

I need to determine if the DataContractJsonSerializer can deserialize JSON to a Dictionary if the Dictionary is not the wrapping object being deserialized. I know there are other open source codes projects that may be able to do this (json.net, json-framework) but I'd like to know definitively if .NET can natively handle this before taking that approach. all the MSDN documentation suggests it can but I am not sure if I am handling the conversion correctly.

So to start I'm receiving a video object from a web service in JSON like this:

{"videos":
 [{
  "id":000000000000,
  "name":"Video Title",
  "adKeys":null,
  "shortDescription":"short description",
  "longDescription":"long description",
  "creationDate":"1282819270274",
  "publishedDate":"1282819270274",
  "lastModifiedDate":"1282857505013",
  "linkURL":null,
  "linkText":null,
  "tags":["tag1","tag2","tag3","tag4","tag5","tag5"],
  "videoStillURL":"",
  "thumbnailURL":"",
  "referenceId":"0000",
  "length":177679,
  "economics":"AD_SUPPORTED",
  "playsTotal":178,
  "playsTrailingWeek":178,
  "customFields":{"custom title":"custom value", "custom title 2":"custom value2"},
  "FLVURL":"",
  "renditions":[]
 }],
"page_number":0,
"page_size":0,
"total_count":1}

I am deserializing this object as a BCQueryResult. The BCQueryResult has a property called Videos that is a BCCollection which extends List and applies a CollectionDataContract. The video object in turn has a property called customFields that is a CustomFields object which extends Dictionary and applies a CollectionDataContract. All collection types that are List types(videos, tags, cuepoints etc.) are deserialized without issue. The Dictionary type is the only type that has a problem deserializing. There is no error but even when a value is present the result is empty. If I strip out all date types and deserialize with the JavaScriptSerializer it will give me the proper value, but because of issues with required field types I cannot use the JavaScriptSerializer instead I am using the DataContractJsonSerializer. I've attached the classes below.

BCQueryResult:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using BrightcoveSDK.Media;

namespace BrightcoveSDK
{
 [DataContract]
 public class BCQueryResult
 {
  [DataMember(Name = "videos")]
  public BCCollection<BCVideo> Videos;
  [DataMember(Name = "playlists")]
  public BCCollection<BCPlaylist> Playlists;
  [DataMember(Name = "page_number")]
  public int PageNumber { get; set; }
  [DataMember(Name = "page_size")]
  public int PageSize { get; set; }
  [DataMember(Name = "total_count")]
  public int TotalCount { get; set; }

  public int MaxToGet = 0;
  public List<QueryResultPair> QueryResults = new List<QueryResultPair>();

  public BCQueryResult() {
   Playlists = new BCCollection<BCPlaylist>();
   Videos = new BCCollection<BCVideo>();
   PageNumber = 0;
   PageSize = 0;
   TotalCount = 0;
  }

  public void Merge(BCQueryResult qr) {

   //if (qr.QueryResults != null && qr.QueryResults.Count > 0)
   //        QueryResults.Add(qr.QueryResults[qr.QueryResults.Count -1]);
   if (qr.Videos != null) Videos.AddRange(qr.Videos);
   if(qr.Playlists != null) Playlists.AddRange(qr.Playlists);
   PageNumber = qr.PageNumber;
   TotalCount = qr.TotalCount;
   PageSize = qr.PageSize;
  }
 }
}

BCCollection:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace BrightcoveSDK
{
 [CollectionDataContract]
 public class BCCollection<T> : List<T>
 {}

 public static class BCCollectionExtensions {

  public static string ToDelimitedString(this BCCollection<string> list, string Delimiter) {

   string r = "";
   foreach (string s in list) {
    if (r.Length > 0) {
     r += Delimiter;
    }
    r += s;
   }
   return r;
  }
 }
}

BCVideo:

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Web;
using System.Runtime.Serialization;

namespace BrightcoveSDK.Media
{
 /// <summary>
 /// The Video object is an aggregation of metadata and asset information associated with a video
 /// </summary>
 [DataContract]
 public class BCVideo : BCObject, IComparable<BCVideo>
 {
  /// <summary>
  /// A number that uniquely identifies this Video, assigned by Brightcove when the Video is created.
  /// </summary>
  [DataMember]
  public long id { get; set; }

  /// <summary>
  /// The title of this Video.
  /// </summary> 
  [DataMember]
  public string name { get; set; }

  /// <summary>
  /// A short description describing this Video, limited to 256 characters.
  /// </summary> 
  [DataMember]
  public string shortDescription { get; set; }

  /// <summary>
  /// A longer description of this Video, bounded by a 1024 character limit.
  /// </summary> 
  [DataMember]
  public string longDescription { get; set; }

  [DataMember(Name = "creationDate")]
  private string createDate { get; set; }

  /// <summary>
  /// The date this Video was created, represented as the number of milliseconds since the Unix epoch.
  /// </summary> 
  public DateTime creationDate {
   get {
    return DateFromUnix(createDate);
   }
   set {
    createDate = DateToUnix(value);
   }
  }

  [DataMember(Name = "publishedDate")]
  private string publishDate { get; set; }

  /// <summary>
  /// The date this Video was last made active, represented as the number of milliseconds since the Unix epoch.
  /// </summary> 
  public DateTime publishedDate {
   get {
    return DateFromUnix(publishDate);
   }
   set {
    publishDate = DateToUnix(value);
   }
  }

  [DataMember(Name = "lastModifiedDate")]
  private string modifyDate { get; set; }

  /// <summary>
  /// The date this Video was last modified, represented as the number of milliseconds since the Unix epoch.
  /// </summary> 
  pu开发者_JAVA技巧blic DateTime lastModifiedDate {
   get {
    return DateFromUnix(modifyDate);
   }
   set {
    modifyDate = DateToUnix(value);
   }
  }

  /// <summary>
  /// An optional URL to a related item.
  /// </summary> 
  [DataMember]
  public string linkURL { get; set; }

  /// <summary>
  /// The text displayed for the linkURL.
  /// </summary> 
  [DataMember]
  public string linkText { get; set; }

  [DataMember(Name = "FLVURL")]
  public string flvURL { get; set; }

        private BCCollection<string> _tags;

  /// <summary>
  /// A list of Strings representing the tags assigned to this Video.
  /// </summary> 
        [DataMember]
        public BCCollection<string> tags {
            get {
                if (_tags == null) {
                    _tags = new BCCollection<string>();
                }
                return _tags;
            }
            set {
                _tags = value;
            }
        }

        private BCCollection<BCCuePoint> _cuePoints;

        /// <summary>
        /// A list of cuePoints representing the cue points assigned to this Video.
        /// </summary> 
        [DataMember]
        public BCCollection<BCCuePoint> cuePoints {
            get {
                if(_cuePoints == null){
                    _cuePoints = new BCCollection<BCCuePoint>();
                }
                return _cuePoints;
            }
            set {
                _cuePoints = value;
            }
        }

  /// <summary>
  /// The URL to the video still image associated with this Video. Video stills are 480x360 pixels.
  /// </summary> 
  [DataMember]
  public string videoStillURL { get; set; }

  /// <summary>
  /// The URL to the thumbnail image associated with this Video. Thumbnails are 120x90 pixels.
  /// </summary> 
  [DataMember]
  public string thumbnailURL { get; set; }

  /// <summary>
  /// A user-specified id that uniquely identifies this Video. ReferenceID can be used as a foreign-key to identify this video in another system. 
  /// </summary> 
  [DataMember]
  public string referenceId { get; set; }

  /// <summary>
  /// The length of this video in milliseconds.
  /// </summary> 
  [DataMember]
  public string length { get; set; }

  [DataMember(Name = "economics")]
  private string ecs { get; set; }

  /// <summary>
  /// Either FREE or AD_SUPPORTED. AD_SUPPORTED means that ad requests are enabled for this Video.
  /// </summary> 
  public BCVideoEconomics economics {
   get {
    if (ecs == null) {
     return BCVideoEconomics.AD_SUPPORTED;
    }
    else if (ecs.Equals(BCVideoEconomics.AD_SUPPORTED.ToString())) {
     return BCVideoEconomics.AD_SUPPORTED;
    }
    else if (ecs.Equals(BCVideoEconomics.FREE.ToString())) {
     return BCVideoEconomics.FREE;
    }
    else {
     return BCVideoEconomics.AD_SUPPORTED;
    }
   }
   set {
    ecs = value.ToString();
   }
  }

  [DataMember(Name = "playsTotal")]
  private string plays { get; set; }

  /// <summary>
  /// How many times this Video has been played since its creation.
  /// </summary> 
  public long playsTotal {
   get {
    if (!String.IsNullOrEmpty(plays)) {
     return long.Parse(plays);
    } else {
     return 0;
    }
   }
   set {
    plays = value.ToString();
   }
  }

  [DataMember(Name = "playsTrailingWeek")]
  private string playsWeek { get; set; }

        public static List<string> VideoFields {
            get {
                List<string> fields = new List<string>();
                foreach (string s in Enum.GetNames(typeof(BrightcoveSDK.VideoFields))) {
                    fields.Add(s);
                }
                return fields;
            }
        }

  /// <summary>
  /// How many times this Video has been played within the past seven days, exclusive of today.
  /// </summary> 
  public long playsTrailingWeek {
   get {
    if(!String.IsNullOrEmpty(playsWeek)) {
     return long.Parse(playsWeek);
    } else {
     return 0;
    }
   }
   set {
    playsWeek = value.ToString();
   }
  }

        [DataMember(Name = "itemState")]
        private string _itemState {get; set;}

        public ItemStateEnum itemState {
            get {
    if (_itemState == null) {
     return ItemStateEnum.ACTIVE;
    }
    else if (_itemState.Equals(ItemStateEnum.ACTIVE.ToString())) {
     return ItemStateEnum.ACTIVE;
    }
    else if (_itemState.Equals(ItemStateEnum.DELETED.ToString())) {
     return ItemStateEnum.DELETED;
    }
                else if (_itemState.Equals(ItemStateEnum.INACTIVE.ToString())) {
     return ItemStateEnum.INACTIVE;
    }
    else {
     return ItemStateEnum.ACTIVE;
    }
   }
   set {
    ecs = value.ToString();
   }
        }

        [DataMember(Name = "version")]
        private string _version {get; set;}

        public long version {
         get {
    if (!String.IsNullOrEmpty(_version)) {
     return long.Parse(_version);
    } else {
     return 0;
    }
   }
   set {
    _version = value.ToString();
   }
        }

        [DataMember]
        public string submissionInfo {get; set;}

        public CustomFields _customFields;

        [DataMember]
        public CustomFields customFields {
            get {
                if (_customFields == null) {
                    _customFields = new CustomFields();
                }
                return _customFields;
            }
            set {
                _customFields = value;
            }
        }

        [DataMember]
        public string releaseDate {get; set;}

        [DataMember]
        public string geoFiltered {get; set;}

        [DataMember]
        public string geoRestricted {get; set;}

        [DataMember]
        public string geoFilterExclude {get; set;}

        [DataMember]
        public string excludeListedCountries {get; set;}

        private BCCollection<string> _geoFilteredCountries;

        [DataMember]
        public BCCollection<string> geoFilteredCountries {
            get {
                if (_geoFilteredCountries == null) {
                    _geoFilteredCountries = new BCCollection<string>();
                }
                return _geoFilteredCountries;
            }
            set {
                _geoFilteredCountries = value;
            }
        }

        private BCCollection<string> _allowedCountries;

        [DataMember]
        public BCCollection<string> allowedCountries {
            get {
                if (_allowedCountries == null) {
                    _allowedCountries = new BCCollection<string>();
                }
                return _allowedCountries;
            }
            set {
                _allowedCountries = value;
            }
        }

        [DataMember(Name = "accountId")]
        private string _accountId {get; set;}

        public long accountId {
         get {
    if (!String.IsNullOrEmpty(_accountId)) {
     return long.Parse(_accountId);
    } else {
     return 0;
    }
   }
   set {
    _accountId = value.ToString();
   }
        }

  public BCVideo() {
  }

  #region IComparable Comparators

  public int CompareTo(BCVideo other) {
   return name.CompareTo(other.name);
  }

  //CREATION_DATE
  public static Comparison<BCVideo> CreationDateComparison =
   delegate(BCVideo v1, BCVideo v2)
   {
    return v1.creationDate.CompareTo(v2.creationDate);
   };

  //PLAYS_TOTAL
  public static Comparison<BCVideo> TotalPlaysComparison =
   delegate(BCVideo v1, BCVideo v2)
   {
    return v1.playsTotal.CompareTo(v2.playsTotal);
   };

  //PUBLISH_DATE
  public static Comparison<BCVideo> PublishDateComparison =
   delegate(BCVideo v1, BCVideo v2)
   {
    return v1.publishedDate.CompareTo(v2.publishedDate);
   };

  //MODIFIED_DATE
  public static Comparison<BCVideo> ModifiedDateComparison =
   delegate(BCVideo v1, BCVideo v2)
   {
    return v1.lastModifiedDate.CompareTo(v2.lastModifiedDate);
   };

  //PLAYS_TRAILING_WEEK
  public static Comparison<BCVideo> PlaysTrailingComparison =
   delegate(BCVideo v1, BCVideo v2)
   {
    return v1.playsTrailingWeek.CompareTo(v2.playsTrailingWeek);
   };

  #endregion
 }

 public static class BCVideoExtensions {

  #region Extension Methods

  public static string ToCreateJSON(this BCVideo video) {
   return ToJSON(video, JSONType.Create);
  }

  public static string ToJSON(this BCVideo video) {
   return ToJSON(video, JSONType.Update);
  }

        private static string ToJSON(this BCVideo video, JSONType type) {

   //--Build Video in JSON -------------------------------------//

            StringBuilder jsonVideo = new StringBuilder();
            jsonVideo.Append("{");

   if(type.Equals(JSONType.Update)){
    //id
    jsonVideo.Append("\"id\": " + video.id.ToString() + ",");
   }

   //name
   if (!string.IsNullOrEmpty(video.name)) {
    jsonVideo.Append("\"name\": \"" + video.name + "\"");
   }

   //shortDescription
   if (!string.IsNullOrEmpty(video.shortDescription)) {
    jsonVideo.Append(",\"shortDescription\": \"" + video.shortDescription + "\"");
   }

   //Tags should be a list of strings
   if (video.tags.Count > 0) {
    jsonVideo.Append(",\"tags\": [");
    string append = "";
    foreach (string tag in video.tags) {
     jsonVideo.Append(append + "\"" + tag + "\"");
     append = ",";
    }
    jsonVideo.Append("]");
   }

   //referenceId
   if (!string.IsNullOrEmpty(video.referenceId)) {
    jsonVideo.Append(",\"referenceId\": \"" + video.referenceId + "\"");
   }

   //longDescription
   if (!string.IsNullOrEmpty(video.longDescription)) {
    jsonVideo.Append(",\"longDescription\": \"" + video.longDescription + "\"");
   }

            if (video.cuePoints.Count > 0) {
                jsonVideo.Append(",\"cuePoints\": " + video.cuePoints.ToJSON());
            }

   //economics
   jsonVideo.Append(",\"economics\": " + video.economics.ToString());

   jsonVideo.Append("}");

   return jsonVideo.ToString();
  }

  #endregion
 }
}

CustomFields:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace BrightcoveSDK
{
    [CollectionDataContract]
    public class CustomFields : Dictionary<string, string>
    { }
}


JSON dictionaries aren't deserialized as dictionaries, but as arrays of KeyValuePair<T,U>

Change your datamember type to KeyValuePair<string, string>[]


The CollectionDataContract attribute can be used to specify a contract that serializes into a JSON "dictionary", namely an array of key-value pair objects. A sample would look something like this:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace DictionarySample
{
    [CollectionDataContract(Name = "dict", ItemName = "key", KeyName = "key", ValueName = "value")]
    public class DictContract : Dictionary<string, string>
    {
        public DictContract() { }
        public DictContract(SerializationInfo info, StreamingContext context : base(info, context) { }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消