Deserializing JSON when sometimes array and sometimes object
The developer of JSON.NET ended up helping on the projects codeplex site. Here is the solution:
The problem was, when it was a JSON object, I wasn't reading past the attribute. Here is the correct code:
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});
}
}
James was also kind enough to provide unit tests for the above method.
Error Deserializing JSON Object/Array using newtonsoft
Look at Camilo Martinez answer on this discussion :
Deserializing JSON when sometimes array and sometimes object
Basically, you'll need to add the JsonConverter
attribute to your BookingInfo
property and handle the conversion in a JsonConverter
implementation.
public class FlightOptionsList
{
public List<FlightOption> FlightOption { get; set; }
}
public class FlightOption
{
public string LegRef { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Option Option { get; set; }
}
public class Option
{
public string Key { get; set; }
public string TravelTime { get; set; }
[JsonConverter(typeof(SingleValueArrayConverter<BookingInfo>))]
public List<BookingInfo> BookingInfo { get; set; }
public Connection Connection { get; set; }
}
public class BookingInfo
{
public string BookingCode { get; set; }
public string BookingCount { get; set; }
public string CabinClass { get; set; }
public string FareInfoRef { get; set; }
public string SegmentRef { get; set; }
}
public class Connection
{
public string SegmentIndex { get; set; }
}
And here's the converter :
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;
}
}
Deserialize json where properties have an object instead of an array when there would be only one entry?
Shortly after posting this I found a blogpost further down in the search results that solves this exact problem:
http://michaelcummings.net/mathoms/using-a-custom-jsonconverter-to-fix-bad-json-results/
edit 2017-07-19: Another blogpost popped up: http://trycatchfail.com/blog/post/Dealing-with-Horrid-No-Good-Very-Bad-APIs-Using-JSONNET
In case it ever goes down, here is the relevant code for a JsonConverter:
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;
}
edit:
What I ended up doing was adding an interface:
public interface IHasContent
{
string Content { get; set; }
}
as at least the string only types always had the same name for those.
the problematic types got the attribute and interface:
[JsonConverter(typeof(SingleValueArrayConverter<ShippingInfo>))]
public class ShippingInfo : IHasContent
For the string conversion I added a simple implicit operator:
public static implicit operator ShippingInfo(string s)
{
return new ShippingInfo { Content = s };
}
The converter got some type constraints:
public class SingleValueArrayConverter<T> : JsonConverter where T : IHasContent, new()
and finally, here is the ReadJson method:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal;
switch (reader.TokenType)
{
case JsonToken.StartObject:
var instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T> { instance };
break;
case JsonToken.StartArray:
retVal = serializer.Deserialize(reader, objectType);
break;
case JsonToken.String:
retVal = ReadStringAsContentObject();
break;
default:
throw new ArgumentException();
}
return retVal;
object ReadStringAsContentObject()
{
var content = new T();
content.Content = reader.ReadAsString();
var returnObject = new List<T> { content };
return returnObject;
}
}
Deserialize JSON as object or array with JSON.Net
You can change the property type for "data" in your model to dynamic or an object and check if it is an array on run-time.
Here's an example:
public class Response
{
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("data")]
public dynamic Data { get; set; }
}
var response = JsonConvert.DeserializeJson<Response>(json);
.
.
.
Type responseDataType = response.Data.GetType();
if(responseDataType.IsArray) {
// It's an array, what to do?
}
else {
// Not an array, what's next?
}
Deserialize JSON, sometimes value is an array, sometimes (blank string)
Yes.
Inside the JsonConverter test the token type from the JsonReader.
If it is a string then return null.
If it is the start of an array then use the JsonReader and JsonSerializer passed to the converter method to deserialize the array.
Related Topics
Best Way to Access a Control on Another Form in Windows Forms
Http Error 500.30 - Ancm In-Process Start Failure
How to Drag and Drop Files into an Application
Does the C# "Finally" Block Always Execute
C# Deserializing a Struct After Receiving It Through Tcp
Dynamically Add C# Properties at Runtime
Best Way to Remove Duplicate Entries from a Data Table
Troubleshooting Badimageformatexception
Why Does This Floating-Point Calculation Give Different Results on Different MAChines
Using Xmlserializer to Serialize Derived Classes
How to Run an Exe Program from a Windows Service Using C#
In Mvvm Should the Viewmodel or Model Implement Inotifypropertychanged
Fire-And-Forget with Async VS "Old Async Delegate"
Adding Multiple Parameterized Variables to a Database in C#
Servicestack Request Dto Design
How to Enumerate All Windows Belonging to a Particular Process Using .Net