This question already has answers here:
How to handle both a single item and an array for the same property using JSON.net
(9 answers)
Closed 5 years ago.
I'm trying to deserialize event data that includes image urls.
When the event includes a single image, the format of the JSON string is:
"images": {
"image": {
"small": {...},
"width": "48",
"creator": null,
"thumb": {...},
"height": "48",
"url": "http://example.com/image1.jpeg",
"medium": {...},
"id": "1"
}
}
When multiple images are available, the format of the response changes to:
"images": {
"image": [
{
"small": {...},
"width": "48",
"creator": null,
"thumb": {...},
"height": "48",
"url": "http://example.com/image1.jpeg",
"medium": {...},
"id": "1"
},
{
"small": {...},
"width": "48",
"creator": null,
"thumb": {...},
"height": "48",
"url": "http://example.com/image2.jpeg",
"medium": {...},
"id": "2"
}
]
}
When I'm trying to deserialize, I can get one or other model to work, but not both at the same time.
My model is something like:
public class Event
{
public string id { get; set; }
public string imageId { get; set; }
public Image image { get; set; }
public Images images { get; set; }
}
public class Image
{
public string id { get; set; }
public string width { get; set; }
public string caption { get; set; }
public string url { get; set; }
public string height { get; set; }
public int smallId { get; set; }
public Small small { get; set; }
public int mediumId { get; set; }
public Medium medium { get; set; }
public int thumbId { get; set; }
public Thumb thumb { get; set; }
}
If I define my Images class as follows, it works with arrays:
public class Images
{
public string id { get; set; }
public List<Image> image { get; set; }
}
If I define it as follows, it works with single images:
public class Images
{
public string id { get; set; }
public Image image { get; set; }
}
In theory, I could contain both a List and an Image in the Images class, but I can't use the same name for both and the deserialization doesn't work if I change either name.
I understand that both responses are valid JSON (they represent what they're supposed to), but is this a bad implementation?
Or am I missing something in my model/deserialization that should allow me to deserialize both the single object and array?
Thanks.
UPDATE
Deserialization code:
var feedUrl = url;
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var serializer = new DataContractJsonSerializer(typeof(EventDetail));
var streamTask = client.GetStreamAsync(feedUrl);
EventDetail eventDetail = serializer.ReadObject(await streamTask) as EventDetail;
return eventDetail;
Similar question was asked in the past: "How to handle both a single item and an array for the same property using JSON.net". The approach is basically to use customConverter as follow:
public class Images
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("image")]
[JsonConverter(typeof(SingleOrArrayConverter<Image>))]
public List<Image> Image { get; set; }
}
public class SingleOrArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List<T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Without seeing your serialization/deserialization code I think the problem is there.
One other Solution could be that you send an empty list of Images (Images) if you only have one Image and the other way around. So you always have Imageand Images in your JSON.
Related
Let's say we have these C# classes:
public class Teacher
{
public long Id { get; set; }
public string Name { get; set; }
public boolean IsActive { get; set; }
public dynamic RelatedItems { get; set; }
}
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
public double AverageScrore { get; set; }
public dynamic RelatedItems { get; set; }
}
public class Course
{
public long Id { get; set; }
public string Title { get; set; }
}
And here's the object graph that is built:
var teacher = teacherService.Get(teacherId);
teacher.RelatedItems.Students = studentService.GetByTeacherId(teacherId);
foreach (var student in teacher.RelatedItems.Students)
{
student.RelatedItems.Courses = courseService.GetStudentCourses(studentId);
}
The object graph above produces this JSON after serialization (using System.Text.Json):
{
"Id": "5",
"Name": "John",
"IsActive": true,
"RelatedItems": {
"Students": [
{
"Id": 7,
"Name": "Joe",
"AverageScore": 9.3,
"RelatedItems": {
"Courses": [
{
"Id": 12,
"Title": "Math"
}
]
}
}
]
}
}
What I need to do is to remove those RelatedItems in the serialized JSON, and move their children one step up. This would be the result:
{
"Id": "5",
"Name": "John",
"IsActive": true,
"Students": [
{
"Id": 7,
"Name": "Joe",
"AverageScore": 9.3,
"Courses": [
{
"Id": 12,
"Title": "Math"
}
]
}
]
}
Is it possible to be done via System.Text.Json?
You have to write custom classes for serialization
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomJsonConverter());
json = JsonSerializer.Serialize(StudentClassObject, options);
Implementation of CustomJsonConverter
public class CustomJsonConverter : JsonConverter<Student>
{
public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Use default implementation when deserializing (reading)
return JsonSerializer.Deserialize<Book>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
writer.WriteStartObject();
using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
{
foreach (var property in document.RootElement.EnumerateObject())
{
if (property.Name != "RelatedItems")
property.WriteTo(writer);
}
}
writer.WriteEndObject();
}
}
I am trying to deserialize a json response I get from a web call. I have it 90 percent figured out. The only part I am having a hard time figuring out is there are these json arrays which have data in them and each array name is unique using the email address. I have not been able to figure out how to turn the Email Arrays into 1. Dynamic and having it create many lists or just a couple depending on what comes back in the response and also dynamically naming the list arrays to put the data into the Records class.
As you can see in the Records class I need this to be more dynamic and flexible to receive any and all emails.
Below is the json:
{
"result": {
"records": {
"joeblow#gmail.com": [
{
"OrderId": "d9535109-d305-4584-a503-8194bbcfcff2",
"CompletedOrderId": "BCFCFF2",
"CustomerId": 1212,
"CompletedTime": "2020-10-26 13:32:02",
"Email": "joeblow#gmail.com",
"ShippingFirstName": "Joe",
"ShippingMiddleName": "",
"ShippingLastName": "Blow",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 }
}
}
],
"cleob#hotmail.com": [
{
"OrderId": "7bf97b3a-bc46-411c-bc30-12563326dba0",
"CompletedOrderId": "326DBA0",
"CustomerId": 1212,
"CompletedTime": "2020-10-26 20:07:44",
"Email": "cleob#hotmail.com",
"ShippingFirstName": "Cleo",
"ShippingMiddleName": "",
"ShippingLastName": "Blue",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 },
"aos.en.pb": { "qty": 1 },
"course-tos.en.olr": { "qty": 1 },
"pow-hsk-nofilm.en.combo": { "qty": 1 },
"course-organizing.en.olr": { "qty": 1 }
}
}
],
"johnd#gmail.com": [
{
"OrderId": "630f0dda-94c3-4b82-a070-2554004dce29",
"CompletedOrderId": "04DCE29",
"CustomerId": 12345,
"CompletedTime": "2020-10-25 21:52:04",
"Email": "johnd#gmail.com",
"ShippingFirstName": "John",
"ShippingMiddleName": "",
"ShippingLastName": "Doe",
"LineItems": {
"tfl.es.bluray": { "qty": 1 },
"booklets.en.ebook": { "qty": 1 },
"aos.en.pb": { "qty": 1 },
"course-tos.en.olr": { "qty": 1 },
"pow-hsk-nofilm.en.combo": { "qty": 1 },
"course-organizing.en.olr": { "qty": 1 },
"oak-2007.en.cd": { "qty": 1 }
}
}
]
},
"errors": [
{
"id": "bademailaddress-yahoo.com",
"message": "Email address 'bademailaddress-yahoo.com' is not a valid email address"
}
]
},
"jsonrpc": "2.0",
"id": 12345634523
}
And the classes I made for the json deserialization:
public partial class JsonEmailDeSerializer
{
[JsonProperty("result")]
public Result Result { get; set; }
[JsonProperty("jsonrpc")]
public string Jsonrpc { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
}
public partial class Result
{
[JsonProperty("records")]
public Records Records { get; set; }
[JsonProperty("errors")]
public List<Error> Errors { get; set; }
}
public partial class Error
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
public partial class Records
{
[JsonProperty("joeblow#gmail.com")]
public List<MailCom> JoeblowGmailCom { get; set; }
[JsonProperty("cleob#hotmail.com")]
public List<MailCom> CleobHotmailCom { get; set; }
[JsonProperty("johnd#gmail.com")]
public List<MailCom> JohndGmailCom { get; set; }
}
public partial class MailCom
{
[JsonProperty("OrderId")]
public Guid OrderId { get; set; }
[JsonProperty("CompletedOrderId")]
public string CompletedOrderId { get; set; }
[JsonProperty("CustomerId")]
public long CustomerId { get; set; }
[JsonProperty("CompletedTime")]
public DateTimeOffset CompletedTime { get; set; }
[JsonProperty("Email")]
public string Email { get; set; }
[JsonProperty("ShippingFirstName")]
public string ShippingFirstName { get; set; }
[JsonProperty("ShippingMiddleName")]
public string ShippingMiddleName { get; set; }
[JsonProperty("ShippingLastName")]
public string ShippingLastName { get; set; }
[JsonProperty("LineItems")]
public Dictionary<string, LineItem> LineItems { get; set; }
}
public partial class LineItem
{
[JsonProperty("qty")]
public long Qty { get; set; }
}
public partial class JsonEmailDeSerializer
{
public static JsonEmailDeSerializer FromJson(string json) => JsonConvert.DeserializeObject<JsonEmailDeSerializer>(json, FedExShipper.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this JsonEmailDeSerializer self) => JsonConvert.SerializeObject(self, FedExShipper.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 }
},
};
}
Common approach to deserializing json with dynamic property names is to use Dictionary<string, ...>, in this case - Dictionary<string, List<MailCom>> can be used for Records property:
public partial class Result
{
[JsonProperty("records")]
public Dictionary<string, List<MailCom>> Records { get; set; }
[JsonProperty("errors")]
public List<Error> Errors { get; set; }
}
Json.NET can treat json object properties as keys for dictionary which makes it suitable to deserialize such dynamic data. The same is true for System.Text.Json.
That will never serialize to a class properly.
You'll have to use a lower-level API like Utf8JsonReader to read that level in the document, at least.
I write an app that gets IMDb movie information by scraping movie page source. Some of the movie data in page source are in JSON format with movie schema from "Schema.org".
{
"#context": "http://schema.org",
"#type": "Movie",
"url": "/title/tt7131622/",
"name": "Once Upon a Time... in Hollywood",
"genre": [
"Comedy",
"Drama"
],
"actor": [
{
"#type": "Person",
"url": "/name/nm0000138/",
"name": "Leonardo DiCaprio"
},
{
"#type": "Person",
"url": "/name/nm0000093/",
"name": "Brad Pitt"
},
{
"#type": "Person",
"url": "/name/nm3053338/",
"name": "Margot Robbie"
},
{
"#type": "Person",
"url": "/name/nm0386472/",
"name": "Emile Hirsch"
}
],
"director": {
"#type": "Person",
"url": "/name/nm0000233/",
"name": "Quentin Tarantino"
},
"creator": [
{
"#type": "Person",
"url": "/name/nm0000233/",
"name": "Quentin Tarantino"
},
{
"#type": "Organization",
"url": "/company/co0050868/"
},
{
"#type": "Organization",
"url": "/company/co0452101/"
},
{
"#type": "Organization",
"url": "/company/co0159772/"
}
}
I made a "Movie" class to deserialize the JSON object. There is a property Person class with the name "Director".
internal class ImdbJsonMovie
{
public string Url { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public List<string> Genre { get; set; }
public List<ImdbJsonPerson> Actor { get; set; }
public ImdbJsonPerson Director { get; set; }
//public string[] Creator { get; set; }
}
It's OK. But the problem is some movies such as "The Matrix" have more than one director.
{
"#context": "http://schema.org",
"#type": "Movie",
"url": "/title/tt0133093/",
"name": "The Matrix",
"genre": [
"Action",
"Sci-Fi"
],
"actor": [
{
"#type": "Person",
"url": "/name/nm0000206/",
"name": "Keanu Reeves"
},
{
"#type": "Person",
"url": "/name/nm0000401/",
"name": "Laurence Fishburne"
},
{
"#type": "Person",
"url": "/name/nm0005251/",
"name": "Carrie-Anne Moss"
},
{
"#type": "Person",
"url": "/name/nm0915989/",
"name": "Hugo Weaving"
}
],
"director": [
{
"#type": "Person",
"url": "/name/nm0905154/",
"name": "Lana Wachowski"
},
{
"#type": "Person",
"url": "/name/nm0905152/",
"name": "Lilly Wachowski"
}
],
"creator": [
{
"#type": "Person",
"url": "/name/nm0905152/",
"name": "Lilly Wachowski"
},
{
"#type": "Person",
"url": "/name/nm0905154/",
"name": "Lana Wachowski"
},
{
"#type": "Organization",
"url": "/company/co0002663/"
},
{
"#type": "Organization",
"url": "/company/co0108864/"
},
{
"#type": "Organization",
"url": "/company/co0060075/"
},
{
"#type": "Organization",
"url": "/company/co0019968/"
},
{
"#type": "Organization",
"url": "/company/co0070636/"
}
}
So it must be List<Person>.
internal class ImdbJsonMovie
{
public string Url { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public List<string> Genre { get; set; }
public List<ImdbJsonPerson> Actor { get; set; }
public List<ImdbJsonPerson> Director { get; set; }
//public string[] Creator { get; set; }
}
Another problem is how to deserialize creator property that is made by the Person class and Organization class.
So the question is "How to deserialize this complex JSON object?"
Thank you
Did you try: https://app.quicktype.io/?l=csharp? It can generate model in C# for you, which is very good begining for further changes (if the Schema has to be different according to different json responses)
I did enter your JSON and the model created is following:
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Movies
{
[JsonProperty("#context")]
public Uri Context { get; set; }
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("genre")]
public List<string> Genre { get; set; }
[JsonProperty("actor")]
public List<Tor> Actor { get; set; }
[JsonProperty("director")]
public List<Tor> Director { get; set; }
[JsonProperty("creator")]
public List<Tor> Creator { get; set; }
}
public partial class Tor
{
[JsonProperty("#type")]
public TypeEnum Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
}
public enum TypeEnum { Organization, Person };
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
TypeEnumConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class TypeEnumConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(TypeEnum) || t == typeof(TypeEnum?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
switch (value)
{
case "Organization":
return TypeEnum.Organization;
case "Person":
return TypeEnum.Person;
}
throw new Exception("Cannot unmarshal type TypeEnum");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (TypeEnum)untypedValue;
switch (value)
{
case TypeEnum.Organization:
serializer.Serialize(writer, "Organization");
return;
case TypeEnum.Person:
serializer.Serialize(writer, "Person");
return;
}
throw new Exception("Cannot marshal type TypeEnum");
}
public static readonly TypeEnumConverter Singleton = new TypeEnumConverter();
}
}
[Update]
As for problems with sometime single, sometime array thing --> look here: How to handle both a single item and an array for the same property using JSON.net
Thank you #Piotr. It completely worked. because your first part of the answer was not correct for me, I rewrite your response as an answer.
as you said the correct answer was in this link.
https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n
So I made this class.
class JsonConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<T>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
and changed my Movie Class to this.
internal class ImdbJsonMovie
{
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("genre")]
[JsonConverter(typeof(JsonConverter<string>))]
public List<string> Genre { get; set; }
[JsonProperty("contentRating")]
public string ContentRating { get; set; }
[JsonProperty("actor")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Actor { get; set; }
[JsonProperty("director")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Director { get; set; }
[JsonProperty("creator")]
[JsonConverter(typeof(JsonConverter<ImdbJsonTypeEnum>))]
public List<ImdbJsonTypeEnum> Creator { get; set; }
}
and this Enum
public class ImdbJsonTypeEnum
{
[JsonProperty("#type")]
public TypeEnum Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
public enum TypeEnum
{
Organization,
Person
};
}
It worked for one director and multi director movies.
Thank you
Okay first of all, the answer is probably very simple... But after 45 minutes of trying and googling I just can't figure it out!
So I have some problems getting this Json to parse correctly. I created the classes with http://json2csharp.com/ only it doesn't tell me the code to parse it.
My current classes:
public class Representations
{
public string thumb { get; set; }
public string large { get; set; }
public string full { get; set; }
}
public class Search
{
public string id { get; set; }
public string file_name { get; set; }
public Representations representations { get; set; }
}
public class SearchQuery
{
public List<Search> search { get; set; }
public int total { get; set; }
}
JSON:
{
"search": [
{
"id": "0300",
"file_name": "0300.JPG",
"representations": {
"thumb": "thumb.jpg",
"large": "large.jpg",
"full": "0300.jpg"
},
},
{
"id": "0000",
"file_name": "0000.JPG",
"representations": {
"thumb": "thumb.jpg",
"large": "large.jpg",
"full": "0000.jpg"
},
},
{
"id": "0d00",
"file_name": "0d00.JPG",
"representations": {
"thumb": "thumb.jpg",
"large": "large.jpg",
"full": "0d00.jpg"
},
}
],
"total": 3
}
and code:
searchresults = JsonConvert.DeserializeObject<List<SearchQuery>>(JSONCode);
You should deserialize to a SearchQuery, not List<SearchQuery>:
SearchQuery result = JsonConvert.DeserializeObject<SearchQuery>(JSONCode);
and then use the search property to access the list of search results:
List<Search> searchResults = result.search;
I am using System.Net.Http.HttpClient, the version currently available in NuGet,
to retrieve data from a service in json format. The data roughly looks like this:
{
"schema": "Listing",
"data": {
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [{
"kind": "type1",
"data": {
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
}
}, {
"kind": "type3",
"data": {
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
}]
}
}
I use HttpContentExtensions.ReadAsAsync<T> to de-serialize that json string into an object graph. The type definitions looks roughly like this:
public class Response
{
public String schema { get;set; }
public ListingData data { get;set; }
}
public class ListingData
{
public string key { get;set; }
public List<OneItem> children { get;set; }
}
Here's the problem: I desire the type of the items in children to vary depending on the kind property. If kind is "type1" then I want to de-serialize an object of... let's call it Type1 . If kind is "type3" then I want an object of type Type3.
Right now, I can deserialize a List<Type1> or a List<Type3>, but I don't know how to tell the de-serialization logic to distinguish between the two.
I could merge all the properties of the "type1" data object and the "type3" data object into a single .NET Type. But the number of properties is large enough that this gets messy.
If the name of the property in the JSON (in this case data) were different, I could distinguish using that. If, for example, the data looked like this:
"children": [{
"kind": "type1",
"t1data": { ... }
}, {
"kind": "type3",
"t3data": { ... }
}]
...then I could do something like this in .NET:
public class OneItem
{
public string kind { get;set; }
public Type1 t1data { get;set; }
public Type3 t3data { get;set; }
}
But my data schema doesn't look like that.
Is it possible to choose the type for de-serialization by the content of the data? In other words,
look at the value of one property (in this case, kind) to determine how to de-serialize the content for another property (in this case, data).
Or is it possible to inject a filter or transformer that acts on the JSON before ReadAsAsync tries to deserialize it?
If so, How?
If you're ok w/ doing some pre-processing on your response and you can use Json.NET, you should be able to do what you want.
Given the following classes:
public class Response
{
public string schema
{
get;
set;
}
public ListingData data
{
get;
set;
}
}
public class ListingData
{
public string key
{
get;
set;
}
public List<object> children
{
get;
set;
}
}
public class Type1
{
public string body
{
get;
set;
}
public string parent_id
{
get;
set;
}
public int report_count
{
get;
set;
}
public string name
{
get;
set;
}
}
public class Type3
{
public string domain
{
get;
set;
}
public bool flagged
{
get;
set;
}
public string category
{
get;
set;
}
public bool saved
{
get;
set;
}
public string id
{
get;
set;
}
public double created
{
get;
set;
}
}
This test passes:
[Test]
public void RoundTrip()
{
var response = new Response
{
schema = "Listing",
data = new ListingData
{
key = "28ba648c-de24-45d4-a7d9-70f810cf5438",
children = new List<object>
{
new Type1
{
body = "Four score and seven years ago...",
parent_id = "2qh3l",
report_count = 0,
name = "c4j6yeh"
},
new Type3
{
domain = "abc.def.com",
flagged = true,
category = "news",
saved = false,
id = "t3dz0",
created = 1335998011.0
}
}
}
};
var jsonSerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Objects
};
string serializedResponse = JsonConvert.SerializeObject(response, jsonSerializerSettings);
Console.WriteLine(serializedResponse);
var roundTrippedResponse = JsonConvert.DeserializeObject<Response>(serializedResponse, jsonSerializerSettings);
Assert.That(roundTrippedResponse.data.children.First().GetType(), Is.EqualTo(typeof(Type1)));
Assert.That(roundTrippedResponse.data.children.Last().GetType(), Is.EqualTo(typeof(Type3)));
}
The output written to the console is:
{
"$type": "Test.Response, Test",
"schema": "Listing",
"data": {
"$type": "Test.ListingData, Test",
"key": "28ba648c-de24-45d4-a7d9-70f810cf5438",
"children": [
{
"$type": "Test.Type1, Test",
"body": "Four score and seven years ago...",
"parent_id": "2qh3l",
"report_count": 0,
"name": "c4j6yeh"
},
{
"$type": "Test.Type3, Test",
"domain": "abc.def.com",
"flagged": true,
"category": "news",
"saved": false,
"id": "t3dz0",
"created": 1335998011.0
}
]
}
}
So if you can transform your received response to match that of Json.NET's expected format, this will work.
To piece all of this together, you would need to write a custom MediaTypeFormatter and pass it to the ReadAsAsync<>() call.