mfa*_*nto 47 c# json json.net facebook-c#-sdk json-deserialization
我在使用JSON.NET库对从Facebook返回的数据进行反序列化时遇到了一些麻烦.
从简单的墙贴文件返回的JSON看起来像:
{
"attachment":{"description":""},
"permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789"
}
Run Code Online (Sandbox Code Playgroud)
为照片返回的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"}}
],
Run Code Online (Sandbox Code Playgroud)
一切都很好,我没有问题.我现在遇到一个来自移动客户端的简单墙帖,其中包含以下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"
Run Code Online (Sandbox Code Playgroud)
这是我反序列化的类:
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; }
}
Run Code Online (Sandbox Code Playgroud)
不使用FacebookMediaJsonConverter,我收到一个错误:无法将JSON对象反序列化为类型'System.Collections.Generic.List`1 [FacebookMedia]'.这是有道理的,因为在JSON中,Media不是一个集合.
我发现这篇文章描述了一个类似的问题,所以我试图沿着这条路走下去:反序列化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
return null;
}
Run Code Online (Sandbox Code Playgroud)
哪个工作正常,除了我现在得到一个新的例外:
在JsonSerializerInternalReader.cs中,CreateValueInternal():反序列化对象时出现意外的标记:PropertyName
reader.Value的值是"永久链接".我可以清楚地看到交换机中没有JsonToken.PropertyName的情况.
在我的转换器中有什么我需要做的事情吗?谢谢你的帮助.
Cam*_*nez 32
有关如何处理此案例的详细说明,请参阅"使用自定义JsonConverter修复错误的JSON结果".
总而言之,您可以扩展默认的JSON.NET转换器
使用问题注释属性
[JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))]
public List<OrderItem> items;
Run Code Online (Sandbox Code Playgroud)扩展转换器以返回所需类型的列表,即使对于单个对象也是如此
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;
}
}
Run Code Online (Sandbox Code Playgroud)正如文章中所提到的,这个扩展并不是完全一般的,但是如果你能得到一个列表就可以了.
mfa*_*nto 22
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});
}
}
Run Code Online (Sandbox Code Playgroud)
詹姆斯也非常友好地为上述方法提供单元测试.
阐述 Martinez 和 mfanto 对 Newtonsoft 的回答。它确实可以与 Newtonsoft 一起使用:
这是使用数组而不是列表(并且命名正确)执行此操作的示例。
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject
|| reader.TokenType == JsonToken.String
|| reader.TokenType == JsonToken.Integer)
{
return new T[] { serializer.Deserialize<T>(reader) };
}
return serializer.Deserialize<T[]>(reader);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在属性上写下:
[JsonProperty("INSURANCE")]
[JsonConverter(typeof(SingleValueArrayConverter<InsuranceInfo>))]
public InsuranceInfo[] InsuranceInfo { get; set; }
Run Code Online (Sandbox Code Playgroud)
Newtonsoft 将为您完成剩下的工作。
return JsonConvert.DeserializeObject<T>(json);
Run Code Online (Sandbox Code Playgroud)
为马丁内斯和姆凡托干杯!
不管你相信与否,这适用于子项目。(甚至可能必须这样做。)所以...在我的 InsuranceInfo 中,如果我有另一个对象/数组混合体,请在该属性上再次使用它。
这还允许您将对象重新序列化回 json。当它重新序列化时,它将始终是一个数组。
基于上面 Camilo Martinez 的回答,这是一种使用JsonConverterC# 8.0的通用版本以及实现序列化部分的更现代、类型安全、更精简和更完整的方法。除了根据问题预期的两个令牌之外,它还抛出异常。代码永远不应该做超过要求的事情,否则您将面临由于处理意外数据而导致未来错误的风险。
internal class SingleObjectOrArrayJsonConverter<T> : JsonConverter<ICollection<T>> where T : class, new()
{
public override void WriteJson(JsonWriter writer, ICollection<T> value, JsonSerializer serializer)
{
serializer.Serialize(writer, value.Count == 1 ? (object)value.Single() : value);
}
public override ICollection<T> ReadJson(JsonReader reader, Type objectType, ICollection<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return reader.TokenType switch
{
JsonToken.StartObject => new Collection<T> {serializer.Deserialize<T>(reader)},
JsonToken.StartArray => serializer.Deserialize<ICollection<T>>(reader),
_ => throw new ArgumentOutOfRangeException($"Converter does not support JSON token type {reader.TokenType}.")
};
}
}
Run Code Online (Sandbox Code Playgroud)
然后这样装饰物业:
[JsonConverter(typeof(SingleObjectOrArrayJsonConverter<OrderItem>))]
public ICollection<OrderItem> items;
Run Code Online (Sandbox Code Playgroud)
我已将属性类型从List<>更改ICollection<>为 JSON POCO 通常只需要这种较弱的类型,但如果List<>需要,则只需在上述所有代码中替换ICollection和Collection使用List。
| 归档时间: |
|
| 查看次数: |
25592 次 |
| 最近记录: |