API retuned json object like below 2 forms.
Form 1
{
"Pricing": [
{
"total": 27,
"currency": "USD",
"charges": [ //Chargers Array
{
"code": "C1",
"currency": "USD",
"rate": 15
},
{
"code": "C45",
"currency": "USD",
"rate": 12
}
]
}
]
}
Form 2
{
"Pricing": [
{
"total": 12,
"currency": "USD",
"charges": { //Chargers single object
"code": "C1",
"currency": "USD",
"rate": 12
}
}
]
}
As you can see sometime chargers object return with array and some times not. My question is how to parse this to C# class object? If I added the C# class like below it cannot be parse properly for Form 2. (Form 1 parsing properly)
public class Charge
{
public string code { get; set; }
public string currency { get; set; }
public decimal rate { get; set; }
}
public class Pricing
{
public decimal total { get; set; }
public string currency { get; set; }
public List<Charge> charges { get; set; } //In Form 2, this should be single object
}
public class MainObj
{
public List<Pricing> Pricing { get; set; }
}
Error occurred when parse with Newtonsoft deserialization.
MainObj obj = JsonConvert.DeserializeObject<MainObj>(json);
Error
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Charge]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'Pricing[0].charges.code', line 1, position 69.
Any common method for parsing, when receiving different type of object types with C#?
(I look into this as well but it's for java. And most of this kind of question raised for java but not C#.)
Yet another way of dealing with this problem is to define a custom JsonConverter which can handle both cases.
class ArrayOrObjectConverter<T> : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
return token.Type == JTokenType.Array
? token.ToObject<List<T>>()
: new List<T> { token.ToObject<T>() };
}
public override bool CanConvert(Type objectType)
=> objectType == typeof(List<T>);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=>throw new NotImplementedException();
}
ReadJson first we get a JToken to be able to determine the read value's Type (kind)
ToObject<List<T>> or ToObject<T>CanConvert we examine that the to be populated property's type is a List<T>
JsonConverter<T> where you don't have to define the CanConvert, its ReadJson can be implemented in a bit more complicated wayWriteJson method
CanWrite property of the base class to always return falseWith this class in our hand you can decorate your properties with a JsonConverterAttribute to tell to the Json.NET how to deal with those properties
public class Pricing
{
public decimal total { get; set; }
public string currency { get; set; }
[JsonConverter(typeof(ArrayOrObjectConverter<Charge>))]
public List<Charge> charges { get; set; }
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With