Deserialize a complex json object c# - c#

I have in such an json object:
{
"status": "Success",
"value": [
[
"2019-10-21T11:48:00Z",
"010719/360",
"hodler#hodler.hodler",
{
"role": "hodler",
"company": "Proximus",
"first_name": "Ivan",
"last_name": "Holms",
"modification_date": "2019-10-21 10:33:39"
}
]
]
}
Before that, I always used var obj = JsonConvert.DeserializeObject<MyDistClass>(json);
But I do not understand how to describe this entity:
"value": [
[
"2019-10-21T11:48:00Z",
"010719/360",
"holder#holder.holder",
{
"role": "holder",
"company": "Proximus",
"first_name": "Marc",
"last_name": "Neukirch",
"modification_date": "2019-10-21T10:33:39"
}
]
]
I tried all the classes I knew, even tried to substitute the tuple, but without result. Help me please.

I would probably use Json.NET to parse the JSON to a JObject, then extract the relevant values from that - using JToken.ToObject<> where possible.
Here's some sample code that appears to work - but needs a lot of validation and general tidying up. It's more about demonstrating the idea than anything else:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("test.json");
Result result = Result.FromJson(json);
Console.WriteLine(result.Status);
Console.WriteLine(result.Values.Count);
Console.WriteLine(result.Values[0].User.FirstName);
}
}
public sealed class Result
{
public string Status { get; }
public IReadOnlyList<ResultValue> Values { get; }
private Result(string status, IReadOnlyList<ResultValue> values) =>
(Status, Values) = (status, values);
public static Result FromJson(string json)
{
JObject parsed = JObject.Parse(json);
string status = (string) parsed["status"];
JArray array = (JArray) parsed["value"];
var values = array.Select(ResultValue.FromJToken).ToList().AsReadOnly();
return new Result(status, values);
}
}
public sealed class ResultValue
{
public DateTime Timestamp { get; }
public string Id { get; }
public string Email { get; }
public User User { get; }
private ResultValue(DateTime timestamp, string id, string email, User user) =>
(Timestamp, Id, Email, User) = (timestamp, id, email, user);
internal static ResultValue FromJToken(JToken token)
{
JArray array = (JArray) token;
DateTime timestamp = (DateTime) array[0];
string id = (string) array[1];
string email = (string) array[2];
User user = array[3].ToObject<User>();
return new ResultValue(timestamp, id, email, user);
}
}
// TODO: Make this immutable, or everything else immutable
public sealed class User
{
[JsonProperty("role")]
public string Role { get; set; }
[JsonProperty("company")]
public string Company { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
[JsonProperty("modification_date")]
public DateTime ModificationDate { get; set; }
}

I was able to generate a converter with
https://app.quicktype.io/?l=csharp
Seems to work pretty well.
Here's the Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace QuickType
{
public partial class Request
{
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("value")]
public ValueElement[][] Value { get; set; }
}
public partial class ValueClass
{
[JsonProperty("role")]
public string Role { get; set; }
[JsonProperty("company")]
public string Company { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
[JsonProperty("modification_date")]
public DateTimeOffset ModificationDate { get; set; }
}
public partial struct ValueElement
{
public string String;
public ValueClass ValueClass;
public static implicit operator ValueElement(string String) => new ValueElement { String = String };
public static implicit operator ValueElement(ValueClass ValueClass) => new ValueElement { ValueClass = ValueClass };
}
internal static class Converter2
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
ValueElementConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ValueElementConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(ValueElement) || t == typeof(ValueElement?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new ValueElement { String = stringValue };
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<ValueClass>(reader);
return new ValueElement { ValueClass = objectValue };
}
throw new Exception("Cannot unmarshal type ValueElement");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (ValueElement)untypedValue;
if (value.String != null)
{
serializer.Serialize(writer, value.String);
return;
}
if (value.ValueClass != null)
{
serializer.Serialize(writer, value.ValueClass);
return;
}
throw new Exception("Cannot marshal type ValueElement");
}
public static readonly ValueElementConverter Singleton = new ValueElementConverter();
}
}
Deserialize like this:
var myObject = JsonConvert.DeserializeObject<Request>(json, Converter2.Settings);

Related

C# serializa json to Dictionary [duplicate]

Given the following json:
[ {"id":"123", ... "data":[{"key1":"val1"}, {"key2":"val2"}], ...}, ... ]
that is part of a bigger tree, how can I deserialize the "data" property into:
List<MyCustomClass> Data { get; set; }
or
List<KeyValuePair> Data { get; set; }
or
Dictionary<string, string> Data { get; set; }
using Json.NET? Either version will do (I prefer List of MyCustomClass though). I already have a class that contains other properties, like this:
public class SomeData
{
[JsonProperty("_id")]
public string Id { get; set; }
...
public List<MyCustomClass> Data { get; set; }
}
where "MyCustomClass" would include just two properties (Key and Value). I noticed there is a KeyValuePairConverter class that sounds like it would do what I need, but I wasn't able to find an example on how to use it. Thanks.
The simplest way is deserialize array of key-value pairs to IDictionary<string, string>:
public class SomeData
{
public string Id { get; set; }
public IEnumerable<IDictionary<string, string>> Data { get; set; }
}
private static void Main(string[] args)
{
var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";
var obj = JsonConvert.DeserializeObject<SomeData>(json);
}
But if you need deserialize that to your own class, it can be looks like that:
public class SomeData2
{
public string Id { get; set; }
public List<SomeDataPair> Data { get; set; }
}
public class SomeDataPair
{
public string Key { get; set; }
public string Value { get; set; }
}
private static void Main(string[] args)
{
var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";
var rawObj = JObject.Parse(json);
var obj2 = new SomeData2
{
Id = (string)rawObj["id"],
Data = new List<SomeDataPair>()
};
foreach (var item in rawObj["data"])
{
foreach (var prop in item)
{
var property = prop as JProperty;
if (property != null)
{
obj2.Data.Add(new SomeDataPair() { Key = property.Name, Value = property.Value.ToString() });
}
}
}
}
See that I khow that Value is string and i call ToString() method, there can be another complex class.
Thanks #Boo for your answer but in my case I needed to take some small adjustements.
This is how my JSON looks like:
{
"rates": {
"CAD": 1.5649,
"CZK": 26.118,
...
},
"base": "EUR",
"date": "2020-08-16"
}
And my DTO looks like the following:
public IDictionary<string, decimal> Rates { get; set; }
public string Base { get; set; }
public DateTime Date { get; set; }
So the only adjustement was to remove the IEnumerable around the IDictionary.
I ended up doing this:
[JsonConverter(typeof(MyCustomClassConverter))]
public class MyCustomClass
{
internal class MyCustomClassConverter : 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)
{
JObject jObject = JObject.Load(reader);
foreach (var prop in jObject)
{
return new MyCustomClass { Key = prop.Key, Value = prop.Value.ToString() };
}
return null;
}
public override bool CanConvert(Type objectType)
{
return typeof(MyCustomClass).IsAssignableFrom(objectType);
}
}
public string Key { get; set; }
public string Value { get; set; }
}
public class Datum
{
public string key1 { get; set; }
public string key2 { get; set; }
}
public class RootObject
{
public string id { get; set; }
public List<Datum> data { get; set; }
}
i used this wizard as well json2csharp.com to generate class for deserialized
for using that
using RestSharp;
using Newtonsoft.Json;
IRestResponse restSharp= callRestGetMethodby_restSharp(api_server_url);
string jsonString= restSharp.Content;
RootObject rootObj= JsonConvert.DeserializeObject<RootObject>(jsonString);
return Json(rootObj);
if you call rest by restsharp
public IRestResponse callRestGetMethodby_restSharp(string API_URL)
{
var client = new RestSharp.RestClient(API_URL);
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("cache-control", "no-cache");
IRestResponse response = client.Execute(request);
return response;
}
also you can get this 6 line of restsharp from getpostman.com tools
You can use public IEnumerable<IDictionary<string, string>> Data as the most answers are recommending, but it is not the best idea, since it creates a new dictionary for each array key value item. I recommend to use List<KeyValuePair<string, string>> instead ( or you can create a custom class as well instead of using KeyValuePair )
var json = "[{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }]";
List<SomeData> listSomeData = JsonConvert.DeserializeObject<List<SomeData>>(json);
public class SomeData
{
[JsonProperty("id")]
public string Id { get; set; }
public List<KeyValuePair<string, string>> Data { get; set; }
[JsonConstructor]
public SomeData(JArray data)
{
Data = data.Select(d => new KeyValuePair<string, string>(
((JObject)d).Properties().First().Name,
((JObject)d).Properties().First().Value.ToString()))
.ToList();
}
}

how to deal with JSON that changes?

I'm sorry for my ignorance since I'm a newbie. I need to check if a twitch stream is live or not. I'm doing this by using HttpClient and GET request. The class TwitchData deserialize JSON as object is the following.
public partial class TwitchData
{
[JsonProperty("data")]
public Datum[] Data { get; set; }
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
public partial class Datum
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("user_id")]
[JsonConverter(typeof(ParseStringConverter))]
public long UserId { get; set; }
[JsonProperty("game_id")]
[JsonConverter(typeof(ParseStringConverter))]
public long GameId { get; set; }
[JsonProperty("community_ids")]
public object[] CommunityIds { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("viewer_count")]
public long ViewerCount { get; set; }
[JsonProperty("started_at")]
public DateTimeOffset StartedAt { get; set; }
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("thumbnail_url")]
public string ThumbnailUrl { get; set; }
}
public partial class Pagination
{
[JsonProperty("cursor")]
public string Cursor { get; set; }
}
public partial class TwitchData
{
public static TwitchData FromJson(string json) => JsonConvert.DeserializeObject<TwitchData>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this TwitchData 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 }
},
};
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
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);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
and I do the request with this
HttpClient client = new HttpClient();
string uri = "https://api.twitch.tv/helix/streams?user_id=59980349";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Client-ID", token);
var result = client.GetStringAsync(uri);
jsonString = result.ToString();
twitchData = PwdResetRequest.FromJson(jsonString);
The problem with this is that the JSON changes if the stream is offline thus making the written class TwitchData useless to be used for JsonConvert.DeserializeObject.
Following are the JSONs for when the stream is online and offline.
{
"data": [
{
"id": "30356128676",
"user_id": "59788312",
"game_id": "498652",
"community_ids": [],
"type": "live",
"title": "A stream",
"viewer_count": 1325,
"started_at": "2018-09-07T16:30:09Z",
"language": "en",
"thumbnail_url": "url"
}
],
"pagination": {
"cursor": "eydBIjpwdWGsLaJhIjp7IkGH4hNl6CH6MXr9"
}
}
and when its offline
{
"data": [],
"pagination": {}
}
I found a solution to my problem. The object I'm creating has 2 variables, Datum[] data and Pagination Pagination. Frankly, if the stream is offline, only change in JSON string (which can be seen in the question) is that both data array and pagination block is empty. By checking the condition of length of these variables (either checking one of them is enough), I can decide if stream is live or offline. For instance for getStreams class,
if (getStreams.Datum.Length != 0) {
return true;
}
else {
return false;
}

Newtonsoft.Json.JsonReaderException is thrown when DeserializeObject<> is called

Excuse my ignorance since I'm a newbie. I'm trying to get stream info from Twitch whether the stream is live or not. I'm doing this by using HttpClient and GET request. The class TwitchData deserialize JSON as object is the following.
public partial class TwitchData
{
[JsonProperty("data")]
public Datum[] Data { get; set; }
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
public partial class Datum
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("user_id")]
[JsonConverter(typeof(ParseStringConverter))]
public long UserId { get; set; }
[JsonProperty("game_id")]
[JsonConverter(typeof(ParseStringConverter))]
public long GameId { get; set; }
[JsonProperty("community_ids")]
public object[] CommunityIds { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("viewer_count")]
public long ViewerCount { get; set; }
[JsonProperty("started_at")]
public DateTimeOffset StartedAt { get; set; }
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("thumbnail_url")]
public string ThumbnailUrl { get; set; }
}
public partial class Pagination
{
[JsonProperty("cursor")]
public string Cursor { get; set; }
}
public partial class TwitchData
{
public static TwitchData FromJson(string json) => JsonConvert.DeserializeObject<TwitchData>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this TwitchData 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 }
},
};
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
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);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
I do the HttpClient GET request with the following
HttpClient client = new HttpClient();
string uri = "https://api.twitch.tv/helix/streams?user_id=59980349";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Client-ID", token);
var result = client.GetStringAsync(uri);
jsonString = result.ToString();
twitchData = PwdResetRequest.FromJson(jsonString);
When this is run, Newtonsoft.Json.JsonReaderException, Unexpected character encountered while parsing value: S. Path '', line 0, position 0 is thrown. Further debugging, I found that the program breaks at line 71 which is
public static TwitchData FromJson(string json) => JsonConvert.DeserializeObject<TwitchData>(json, QuickType.Converter.Settings);
since I got this class from json2csharp.com, I don't know how to fix that line or why the Exception is thrown.
EDIT:
JSON is requested in comments. This is the JSON if the stream is live
{
"data": [
{
"id": "30356128676",
"user_id": "59788312",
"game_id": "498652",
"community_ids": [],
"type": "live",
"title": "A stream",
"viewer_count": 1325,
"started_at": "2018-09-07T16:30:09Z",
"language": "en",
"thumbnail_url": "url"
}
],
"pagination": {
"cursor": "eydBIjpwdWGsLaJhIjp7IkGH4hNl6CH6MXr9"
}
}
and when its offline
{
"data": [],
"pagination": {}
}

Proper way for child-classes to have common properties with different types

I have a JSON object that will be formatted as such:
{
"myNodes": [
{
"param1": 1,
"param2": "myValue2a",
"param3": {
"myParam3param": 0
}
},
{
"param1": 1,
"param2": "myValue2b",
"param3": [
{
"myItemA": "abc",
"myItemB": "def",
"myItemC": "0"
}]
},
{
"param1": 1,
"param2": "myValue2c",
"param3": [
{
"myItemA": "ghi",
"myItemB": "jkl",
"myItemC": "0"
}]
}]
}
In C#, I'm wondering how to structure response objects to handle this. I'm guessing I'll have some sort of parent class or interface that contains param1, param2, and param3. However, param3 will need to be declared as type "object", and sometimes it will be an object w/ myParam3param, and other times it will be a list of things. I'm also guessing that I should use child classes that determine what type param3 is.
Is this possible? How should this be accomplished... an abstract class or interface?
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class ChildClasses
{
[JsonProperty("myNodes")]
public List<MyNode> MyNodes { get; set; }
}
public partial class MyNode
{
[JsonProperty("param1")]
public long Param1 { get; set; }
[JsonProperty("param2")]
public string Param2 { get; set; }
[JsonProperty("param3")]
public Param3Union Param3 { get; set; }
}
public partial class Param3Element
{
[JsonProperty("myItemA")]
public string MyItemA { get; set; }
[JsonProperty("myItemB")]
public string MyItemB { get; set; }
[JsonProperty("myItemC")]
public string MyItemC { get; set; }
}
public partial class PurpleParam3
{
[JsonProperty("myParam3param")]
public long MyParam3Param { get; set; }
}
public partial struct Param3Union
{
public List<Param3Element> Param3ElementArray;
public PurpleParam3 PurpleParam3;
public bool IsNull => Param3ElementArray == null && PurpleParam3 == null;
}
public partial class ChildClasses
{
public static ChildClasses FromJson(string json) => JsonConvert.DeserializeObject<ChildClasses>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this ChildClasses 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 Param3UnionConverter(),
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class Param3UnionConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(Param3Union) || t == typeof(Param3Union?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
switch (reader.TokenType)
{
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<PurpleParam3>(reader);
return new Param3Union { PurpleParam3 = objectValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<List<Param3Element>>(reader);
return new Param3Union { Param3ElementArray = arrayValue };
}
throw new Exception("Cannot unmarshal type Param3Union");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (Param3Union)untypedValue;
if (value.Param3ElementArray != null)
{
serializer.Serialize(writer, value.Param3ElementArray); return;
}
if (value.PurpleParam3 != null)
{
serializer.Serialize(writer, value.PurpleParam3); return;
}
throw new Exception("Cannot marshal type Param3Union");
}
}`

Deserialize nested ICollection<BaseType> in Asp.Net Web API 2 controller

I have a Web Api Controller like this one :
public IHttpActionResult Create(PaymentDTO Payment)
My DTOs are:
public class PaymentDTO
{
public int Id { get; set; }
public string type { get; set; }
public IEnumerable<TransactionDTO> Transactions { get; set; }
}
public class TransactionDTO
{
public int Id { get; set; }
public string Description { get; set; }
public string CreateTime { get; set; }
public string UpdateTime { get; set; }
}
public class SaleDTO : TransactionDTO
{
public string Total { get; set; }
public string Currency{ get; set; }
}
public class OrderDTO : TransactionDTO
{
public string State {get;set;}
}
I receive the following JSON formatted data :
{
"Type": "sale",
"Id": 101,
"transactions": [
{
"Total": "30.50",
"Currency": "USD",
"Description": "transaction description"
}
]
}
I want JSON.net to instantiate either a IEnumerable<SaleDTO> or IEnumerable<OrderDTO> based on the Type Property.
I could've used a custom type converter, but only if Type property was in TransactionDTO. But I want the Type property to be in the parent object (PaymentDTO)
Thank you in advance for your help.
You can do this with a custom JsonConverter on the PaymentDTO class:
public class PaymentDTOConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(PaymentDTO).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var obj = JObject.Load(reader);
var payment = (PaymentDTO)existingValue ?? new PaymentDTO();
// Extract the transactions.
var transactions = obj.Property("transactions") ?? obj.Property("Transactions");
if (transactions != null)
transactions.Remove();
// Populate the remaining regular properties.
using (var subReader = obj.CreateReader())
serializer.Populate(subReader, payment);
if (transactions != null)
{
// Deserialize the transactions list.
var type = PaymentDTO.GetTransactionDTOType(payment.type) ?? typeof(TransactionDTO);
using (var subReader = transactions.Value.CreateReader())
// Here we are taking advantage of array covariance.
payment.Transactions = (IEnumerable<TransactionDTO>)serializer.Deserialize(subReader, type.MakeArrayType());
}
return payment;
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Then apply it to your PaymentDTO class as follows:
[JsonConverter(typeof(PaymentDTOConverter))]
public class PaymentDTO
{
static Dictionary<string, Type> namesToTransactions;
static Dictionary<Type, string> transactionsToNames = new Dictionary<Type, string>
{
{ typeof(SaleDTO), "sale" },
{ typeof(OrderDTO), "order" },
};
static PaymentDTO()
{
namesToTransactions = transactionsToNames.ToDictionary(p => p.Value, p => p.Key);
}
public static string GetTransactionDTOTypeName<TTransactionDTO>() where TTransactionDTO : TransactionDTO
{
string name;
if (transactionsToNames.TryGetValue(typeof(TTransactionDTO), out name))
return name;
return null;
}
public static Type GetTransactionDTOType(string name)
{
Type type;
if (namesToTransactions.TryGetValue(name, out type))
return type;
return null;
}
public int Id { get; set; }
public string type { get; set; }
[JsonProperty("transactions")]
public IEnumerable<TransactionDTO> Transactions { get; set; }
}

Categories

Resources