C# 当对象类属性不需要数据时,如何完全防止JSONVERT反序列化对象错误?
我经常使用为Json数据响应创建C#类,我经常发现,如果插入到类生成器中的Json的特定快照缺少数据,那么我就没有正确的类属性来处理数据,这可能导致未处理的反序列化错误。 以下是一个例子:C# 当对象类属性不需要数据时,如何完全防止JSONVERT反序列化对象错误?,c#,json,json-deserialization,C#,Json,Json Deserialization,我经常使用为Json数据响应创建C#类,我经常发现,如果插入到类生成器中的Json的特定快照缺少数据,那么我就没有正确的类属性来处理数据,这可能导致未处理的反序列化错误。 以下是一个例子: "toasts": { "total_count": 1, "count": 1, "auth_toast": false, "items": [ { "uid": 3250810,
"toasts": {
"total_count": 1,
"count": 1,
"auth_toast": false,
"items": [
{
"uid": 3250810,
"user": {
"uid": 3250810,
"user_name": "jdoe",
"first_name": "Jane",
"last_name": "Doe",
"bio": "",
"location": "",
"relationship": "friends",
"user_avatar": "",
"account_type": "user",
"venue_details": [
],
"brewery_details": [
]
},
"like_id": 488764809,
"like_owner": false,
"created_at": "Fri, 16 Mar 2018 20:35:44 +0000"
}
]
},
在该示例中,“场馆详细信息:”下没有数据,因此未发现任何属性,生成的C类如下所示:
public class ViewCheckinID_Toasts
{
public int total_count { get; set; }
public int count { get; set; }
public bool auth_toast { get; set; }
public List<ViewCheckinID_Item2> items { get; set; }
}
public class ViewCheckinID_Item2
{
public int uid { get; set; }
public ViewCheckinID_User2 user { get; set; }
public int like_id { get; set; }
public bool like_owner { get; set; }
public string created_at { get; set; }
}
public class ViewCheckinID_User2
{
public int uid { get; set; }
public string user_name { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string bio { get; set; }
public string location { get; set; }
public string relationship { get; set; }
public string user_avatar { get; set; }
public string account_type { get; set; }
public object[] venue_details { get; set; }
public object[] brewery_details { get; set; }
public string user_link { get; set; }
}
所以现在它不是一个数组,而是一个字符串属性。最终导致以下内容的反序列化错误:
JsonSerializationException:无法将当前JSON对象(例如{“名称”:“值”})反序列化为类型“System.object[]”,因为该类型需要JSON数组(例如[1,2,3])才能正确反序列化。
若要修复此错误,请将JSON更改为JSON数组(例如[1,2,3]),或更改反序列化类型,使其成为可以从JSON对象反序列化的正常.NET类型(例如,不是integer之类的基元类型,也不是数组或列表之类的集合类型)。还可以将JsonObjectAttribute添加到类型中,以强制它从JSON对象反序列化。
路径“response.checkin.toasts.items[0]。用户。场馆详细信息。场馆id”,第143行,位置20
如果我使用新的Json并再次通过C#classes生成器运行它,那么我会得到这个已修复的属性,然后错误就会消失:
public class ViewCheckinID_User2
{
public int uid { get; set; }
public string user_name { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string bio { get; set; }
public string location { get; set; }
public string relationship { get; set; }
public string user_avatar { get; set; }
public string account_type { get; set; }
public ViewCheckinID_VenueDetails venue_details { get; set; }
public object[] brewery_details { get; set; }
public string user_link { get; set; }
}
public class ViewCheckinID_VenueDetails
{
public int venue_id { get; set; }
}
我想做的是能够抵御这个错误。我一直在使用这些帮助器类进行反序列化,但它不能处理这种情况:
string strFileName = @"C:\Users\rick\Documents\files\dev\Explorer\DataModels\ricke_Checkin_View_CheckinID.json";
var resolver = new DefaultContractResolver(); // Cache for performance
var Serializersettings = new JsonSerializerSettings
{
ContractResolver = resolver,
Converters = { new IgnoreUnexpectedArraysConverter(resolver) },
};
ViewCheckinID_RootObject checkinInfo = JsonConvert.DeserializeObject<ViewCheckinID_RootObject>(File.ReadAllText(strFileName), Serializersettings);
public class IgnoreUnexpectedArraysConverter<T> : IgnoreUnexpectedArraysConverterBase
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
}
public class IgnoreUnexpectedArraysConverter : IgnoreUnexpectedArraysConverterBase
{
readonly IContractResolver resolver;
public IgnoreUnexpectedArraysConverter(IContractResolver resolver)
{
if (resolver == null)
throw new ArgumentNullException();
this.resolver = resolver;
}
public override bool CanConvert(Type objectType)
{
if (objectType.IsPrimitive || objectType == typeof(string))
return false;
return resolver.ResolveContract(objectType) is JsonObjectContract;
}
}
public abstract class IgnoreUnexpectedArraysConverterBase : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
if (!(contract is JsonObjectContract))
{
throw new JsonSerializationException(string.Format("{0} is not a JSON object", objectType));
}
do
{
if (reader.TokenType == JsonToken.Null)
return null;
else if (reader.TokenType == JsonToken.Comment)
continue;
else if (reader.TokenType == JsonToken.StartArray)
{
var array = JArray.Load(reader);
if (array.Count > 0)
throw new JsonSerializationException(string.Format("Array was not empty."));
return existingValue ?? contract.DefaultCreator();
}
else if (reader.TokenType == JsonToken.StartObject)
{
// Prevent infinite recursion by using Populate()
existingValue = existingValue ?? contract.DefaultCreator();
*** serializer.Populate(reader, existingValue);
return existingValue;
}
else
{
throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
}
}
while (reader.Read());
throw new JsonSerializationException("Unexpected end of JSON.");
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
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;
}
}
string strFileName=@“C:\Users\rick\Documents\files\dev\Explorer\DataModels\ricke\u Checkin\u View\u CheckinID.json”;
var resolver=new DefaultContractResolver();//性能缓存
var Serializersettings=new JsonSerializerSettings
{
合同解析程序=解析程序,
转换器={new IgnoreUnexpectedArraysConverter(解析器)},
};
ViewCheckinID\u RootObject checkinInfo=JsonConvert.DeserializeObject(File.ReadAllText(strFileName),SerializeSettings);
公共类IgnoreUnexpectedArraysConverter:IgnoreUnexpectedArraysConverterBase
{
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(T).IsAssignableFrom(objectType);
}
}
公共类IgnoreUnexpectedArraysConverter:IgnoreUnexpectedArraysConverterBase
{
只读IContractResolver解析器;
公共信号意外阵列转换器(IContractResolver resolver)
{
if(解析器==null)
抛出新ArgumentNullException();
this.resolver=解析器;
}
公共覆盖布尔CanConvert(类型objectType)
{
if(objectType.IsPrimitive | | objectType==typeof(string))
返回false;
返回解析器。ResolveContract(objectType)为JsonObjectContract;
}
}
公共抽象类IgnoreUnexpectedArraysConverterBase:JsonConverter
{
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
var contract=serializer.ContractResolver.ResolveContract(objectType);
如果(!(合同为JsonObjectContract))
{
抛出新的JsonSerializationException(string.Format(“{0}不是JSON对象”,objectType));
}
做
{
if(reader.TokenType==JsonToken.Null)
返回null;
else if(reader.TokenType==JsonToken.Comment)
继续;
else if(reader.TokenType==JsonToken.StartArray)
{
var数组=JArray.Load(读卡器);
如果(array.Count>0)
抛出新的JsonSerializationException(string.Format(“数组不是空的”);
返回现有值??contract.DefaultCreator();
}
else if(reader.TokenType==JsonToken.StartObject)
{
//使用Populate()防止无限递归
existingValue=existingValue??contract.DefaultCreator();
***序列化程序。填充(读取器,现有值);
返回现有值;
}
其他的
{
抛出新的JsonSerializationException(string.Format(“意外标记{0}”,reader.TokenType));
}
}
while(reader.Read());
抛出新的JsonSerializationException(“JSON意外结束”);
}
公共重写bool可以写入{get{return false;}}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
}
公共类SingleValueArrayConverter:JsonConverter
{
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
object retVal=新对象();
if(reader.TokenType==JsonToken.StartObject)
{
反序列化(reader,typeof(T));
retVal=new List(){instance};
}else if(reader.TokenType==JsonToken.StartArray){
retVal=序列化程序。反序列化(读取器,对象类型);
}
返回返回;
}
公共覆盖布尔CanConvert(类型objectType)
{
返回true;
}
}
如果在帮助器类中看到IgnoreUnexpectedArraysConver
string strFileName = @"C:\Users\rick\Documents\files\dev\Explorer\DataModels\ricke_Checkin_View_CheckinID.json";
var resolver = new DefaultContractResolver(); // Cache for performance
var Serializersettings = new JsonSerializerSettings
{
ContractResolver = resolver,
Converters = { new IgnoreUnexpectedArraysConverter(resolver) },
};
ViewCheckinID_RootObject checkinInfo = JsonConvert.DeserializeObject<ViewCheckinID_RootObject>(File.ReadAllText(strFileName), Serializersettings);
public class IgnoreUnexpectedArraysConverter<T> : IgnoreUnexpectedArraysConverterBase
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
}
public class IgnoreUnexpectedArraysConverter : IgnoreUnexpectedArraysConverterBase
{
readonly IContractResolver resolver;
public IgnoreUnexpectedArraysConverter(IContractResolver resolver)
{
if (resolver == null)
throw new ArgumentNullException();
this.resolver = resolver;
}
public override bool CanConvert(Type objectType)
{
if (objectType.IsPrimitive || objectType == typeof(string))
return false;
return resolver.ResolveContract(objectType) is JsonObjectContract;
}
}
public abstract class IgnoreUnexpectedArraysConverterBase : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
if (!(contract is JsonObjectContract))
{
throw new JsonSerializationException(string.Format("{0} is not a JSON object", objectType));
}
do
{
if (reader.TokenType == JsonToken.Null)
return null;
else if (reader.TokenType == JsonToken.Comment)
continue;
else if (reader.TokenType == JsonToken.StartArray)
{
var array = JArray.Load(reader);
if (array.Count > 0)
throw new JsonSerializationException(string.Format("Array was not empty."));
return existingValue ?? contract.DefaultCreator();
}
else if (reader.TokenType == JsonToken.StartObject)
{
// Prevent infinite recursion by using Populate()
existingValue = existingValue ?? contract.DefaultCreator();
*** serializer.Populate(reader, existingValue);
return existingValue;
}
else
{
throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
}
}
while (reader.Read());
throw new JsonSerializationException("Unexpected end of JSON.");
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
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;
}
}
{
"toasts":[
{
"total_count":1,
"count":1,
"auth_toast":false,
"items":[
{
"uid":3250810,
"user":{
"uid":3250810,
"user_name":"jdoe",
"first_name":"Jane",
"last_name":"Doe",
"bio":"",
"location":"",
"relationship":"friends",
"user_avatar":"",
"account_type":"user",
"venue_details":[
],
"brewery_details":[
]
},
"like_id":488764809,
"like_owner":false,
"created_at":"Fri, 16 Mar 2018 20:35:44 +0000"
}
]
}
]
}
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using QuickType;
//
// var welcome = Welcome.FromJson(jsonString);
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Welcome
{
[JsonProperty("toasts", NullValueHandling = NullValueHandling.Ignore)]
public Toast[] Toasts { get; set; }
}
public partial class Toast
{
[JsonProperty("total_count", NullValueHandling = NullValueHandling.Ignore)]
public long? TotalCount { get; set; }
[JsonProperty("count", NullValueHandling = NullValueHandling.Ignore)]
public long? Count { get; set; }
[JsonProperty("auth_toast", NullValueHandling = NullValueHandling.Ignore)]
public bool? AuthToast { get; set; }
[JsonProperty("items", NullValueHandling = NullValueHandling.Ignore)]
public Item[] Items { get; set; }
}
public partial class Item
{
[JsonProperty("uid", NullValueHandling = NullValueHandling.Ignore)]
public long? Uid { get; set; }
[JsonProperty("user", NullValueHandling = NullValueHandling.Ignore)]
public User User { get; set; }
[JsonProperty("like_id", NullValueHandling = NullValueHandling.Ignore)]
public long? LikeId { get; set; }
[JsonProperty("like_owner", NullValueHandling = NullValueHandling.Ignore)]
public bool? LikeOwner { get; set; }
[JsonProperty("created_at", NullValueHandling = NullValueHandling.Ignore)]
public string CreatedAt { get; set; }
}
public partial class User
{
[JsonProperty("uid", NullValueHandling = NullValueHandling.Ignore)]
public long? Uid { get; set; }
[JsonProperty("user_name", NullValueHandling = NullValueHandling.Ignore)]
public string UserName { get; set; }
[JsonProperty("first_name", NullValueHandling = NullValueHandling.Ignore)]
public string FirstName { get; set; }
[JsonProperty("last_name", NullValueHandling = NullValueHandling.Ignore)]
public string LastName { get; set; }
[JsonProperty("bio", NullValueHandling = NullValueHandling.Ignore)]
public string Bio { get; set; }
[JsonProperty("location", NullValueHandling = NullValueHandling.Ignore)]
public string Location { get; set; }
[JsonProperty("relationship", NullValueHandling = NullValueHandling.Ignore)]
public string Relationship { get; set; }
[JsonProperty("user_avatar", NullValueHandling = NullValueHandling.Ignore)]
public string UserAvatar { get; set; }
[JsonProperty("account_type", NullValueHandling = NullValueHandling.Ignore)]
public string AccountType { get; set; }
[JsonProperty("venue_details", NullValueHandling = NullValueHandling.Ignore)]
public object[] VenueDetails { get; set; }
[JsonProperty("brewery_details", NullValueHandling = NullValueHandling.Ignore)]
public object[] BreweryDetails { get; set; }
}
public partial class Welcome
{
public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters = {
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}