2011-03-07 163 views
34

我在使用JSON.NET库反序列化从Facebook返回的数据时遇到了一些麻烦。反序列化JSON有时是数组,有时是对象

的JSON从只是一个简单的墙后返回的样子:

{ 
    "attachment":{"description":""}, 
    "permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789" 
} 

的JSON返回相片看起来像:

"attachment":{ 
     "media":[ 
      { 
       "href":"http://www.facebook.com/photo.php?fbid=12345", 
       "alt":"", 
       "type":"photo", 
       "src":"http://photos-b.ak.fbcdn.net/hphotos-ak-ash1/12345_s.jpg", 
       "photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}} 
     ], 

一切的伟大工程,我没有问题。现在我遇到一个简单的墙后,从移动客户端与以下JSON,和反序列化失败,现在这一个单一的差价:

"attachment": 
    { 
     "media":{}, 
     "name":"", 
     "caption":"", 
     "description":"", 
     "properties":{}, 
     "icon":"http://www.facebook.com/images/icons/mobile_app.gif", 
     "fb_object_type":"" 
    }, 
"permalink":"http://www.facebook.com/1234" 

这里是我反序列化的类:

public class FacebookAttachment 
    { 
     public string Name { get; set; } 
     public string Description { get; set; } 
     public string Href { get; set; } 
     public FacebookPostType Fb_Object_Type { get; set; } 
     public string Fb_Object_Id { get; set; } 

     [JsonConverter(typeof(FacebookMediaJsonConverter))] 
     public List<FacebookMedia> { get; set; } 

     public string Permalink { get; set; } 
    } 

没有使用FacebookMediaJsonConverter,我得到一个错误:无法将JSON对象反序列化到类型'System.Collections.Generic.List`1 [FacebookMedia]'中。 这是有道理的,因为在JSON中,媒体不是一个集合。

我发现这个职位描述了一个类似的问题,所以我已经试图沿着这条路走下去:Deserialize JSON, sometimes value is an array, sometimes "" (blank string)

我的转换器看起来像:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
{ 
    if (reader.TokenType == JsonToken.StartArray) 
      return serializer.Deserialize<List<FacebookMedia>>(reader); 
    else 
      return null; 
} 

除了我的正常工作,现在得到一个新的异常:

里面JsonSerializerInternalReader.cs,CreateValueInternal():意外令牌反序列化对象:属性名

reader.Value的值是“永久链接”。我可以清楚地看到在开关中没有JsonToken.PropertyName的情况。

有什么我需要在我的转换器有不同的做法吗?谢谢你的帮助。

回答

20

JSON.NET的开发商最终帮助上项目的CodePlex网站下面是解:。

的问题是,当它是一个JSON对象,我不读过去的属性。以下是正确的代码:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
{ 
    if (reader.TokenType == JsonToken.StartArray) 
    { 
     return serializer.Deserialize<List<FacebookMedia>>(reader); 
    } 
    else 
    { 
     FacebookMedia media = serializer.Deserialize<FacebookMedia>(reader); 
     return new List<FacebookMedia>(new[] {media}); 
    } 
} 

詹姆斯还非常友好地为上述方法提供单元测试。

2

看看C#框架中的System.Runtime.Serialization命名空间,它会让你到达你想要的地方。

如果你愿意,你可以在this项目(不是想插入我自己的工作,检查了一些示例代码,但我刚刚完成了相当多,你在做什么,但有不同的源API。

希望帮助

+1

-1通过第三方库推荐使用框架的内部验证部分,并链接到代码示例? – jonezy 2011-03-07 21:06:09

+0

似乎非常不寻常。 – jonezy 2011-03-07 21:06:30

+0

我不确定-1从哪里来。我很欣赏这种回应。我怀疑它可能来自它是一个小问题的相当重量级的解决方案(很可能是由于我自己滥用JSON.NET)。话虽如此,我将尝试尝试Systme.Runtime.Serialization方法,看看它是否最终能够更好地工作。感谢您的链接。 – mfanto 2011-03-07 21:37:47

-2

我觉得你应该这样写你的课...... !!!

public class FacebookAttachment 
    { 

     [JsonProperty("attachment")] 
     public Attachment Attachment { get; set; } 

     [JsonProperty("permalink")] 
     public string Permalink { get; set; } 
    } 

public class Attachment 
    { 

     [JsonProperty("media")] 
     public Media Media { get; set; } 

     [JsonProperty("name")] 
     public string Name { get; set; } 

     [JsonProperty("caption")] 
     public string Caption { get; set; } 

     [JsonProperty("description")] 
     public string Description { get; set; } 

     [JsonProperty("properties")] 
     public Properties Properties { get; set; } 

     [JsonProperty("icon")] 
     public string Icon { get; set; } 

     [JsonProperty("fb_object_type")] 
     public string FbObjectType { get; set; } 
    } 
public class Media 
    { 
    } 
public class Properties 
    { 
    } 
19

关于如何处理这种情况的非常详细的解释可在"Using a Custom JsonConverter to fix bad JSON results"

总之,你可以扩展默认JSON.NET转换器做

  1. 标注的属性与问题

    [JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))] 
    public List<OrderItem> items; 
    
  2. 扩展器来回报您所需类型的列表,甚至对于单个物体

    public class SingleValueArrayConverter<T> : JsonConverter 
    { 
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         object retVal = new Object(); 
         if (reader.TokenType == JsonToken.StartObject) 
         { 
          T instance = (T)serializer.Deserialize(reader, typeof(T)); 
          retVal = new List<T>() { instance }; 
         } else if (reader.TokenType == JsonToken.StartArray) { 
          retVal = serializer.Deserialize(reader, objectType); 
         } 
         return retVal; 
        } 
    
        public override bool CanConvert(Type objectType) 
        { 
         return true; 
        } 
    } 
    

正如文章中提到的那样,这个扩展并不是完全一般的,但是如果你对获得一个清单很好,它就可以工作。

+0

绝对完美。谢谢。 – NotMe 2015-03-06 00:38:10

+0

我很困惑 - 我的WriteJson投掷不执行?我需要处理这个吗? – nologo 2017-04-03 12:01:27