I need a JsonConverter that can handle the following Json Structure. I always want back the segment model for each object in the "segments" collection in the Json. The problem I am having is how to handle the multiple structures in the Json. I am somewhat familiar with writing JsonConverters but this one has me stumped. I asked the partner we are working with if it was possible to standardize the response and was told no.
{
"segments": [
{
"headers" :
{
"agent":"000000000049",
"end_use":"consumer"
},
"data" : {
"vsd_id": "FI_444_56",
"name": "Filler Segment 4inx4inx2in",
"price":"00900",
"lead_time":"4-6"
"certificate": "BR22"
}
},
{
"vsd_id": "RB_190_01",
"name": "Rod Backer 94in",
"price":"05000",
"lead_time":"4-6"
"certificate": "BR23"
}
]
}
public class SegmentRepository {
private Newtonsoft.Json.JsonSerializer _serializer;
private HttpClient _client;
public async Task<IList<Segment>> GetSegments(....)
{
// more code here that builds the requestMessage. not important
using (var responseMessage = await _client.SendAsync(requestMessage))
using (var content = await responseMessage.Content.ReadAsStreamAsync())
using (var textReader = new StreamReader(content))
using (var reader = new JsonTextReader(textReader))
{
var response = _serializer.Deserialize<Response>(reader);
return response.Segments;
}
}
}
public class Response
{
[JsonProperty("segments")]
public List<Segment> Segments {get;set;}
}
public class Segment
{
[JsonProperty("headers")]
public Dictionary<string,string> Headers {get;set;}
[JsonProperty("data")]
public SegmentData Data {get;set;}
}
public class SegmentData
{
[JsonProperty("vsd_id")]
public string Id {get;set;}
[JsonProperty("name")]
public string Name {get;set;}
[JsonConverter(typeof(PriceConverter))]
public Decimal Price {get;set;}
[JsonProperty("lead_time")]
[JsonConverter(typeof(LeadTime))]
public LeadTime LeadTime {get;set;}
[JsonProperty("certificate")]
public string Certificate {get;set;}
}
NOTE: I have already asked the onwer of the API if they could standardize their responses and was told no.
I figured out how to do it. It's quite a simple solution once I figured it out. The piece I was missing for awhile was that I should decorate the class with the JsonCoverter attribute instead of a property.
[JsonConverter(typeof(SegmentsConverter))]
public class Segment
{
[JsonProperty("headers")]
public Dictionary<string, string> Headers { get; set; }
[JsonProperty("data")]
public SegmentData Data { get; set; }
}
public class SegmentsConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jObject = JObject.Load(reader);
if (FieldExists(jObject, "headers"))
{
var target = new Segment();
serializer.Populate(jObject.CreateReader(), target);
return target;
}
else
{
var container = new Segment();
var data = new SegmentData();
container.Data = data;
serializer.Populate(jObject.CreateReader(), data);
return container;
}
}
private bool FieldExists(JObject jObject, string fieldName)
{
return jObject[fieldName] != null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Related
I am stuck at a problem with this, my current base API class implements getting an object from an API like this:
HttpResponceMessage GetResponce(string path) => Task.Run(async() => await client.GetAsync(path));
T GetTFromRequest<T>(string path, JsonConverter[] converters) =>
Task.Run(async() => await GetResponce(path).Content.ReadAsAsync<T>(converters); // Converters gets put into a new JsonMediaTypeFormatter
These are used in other classes to make quick methods. Class Example:
public class ExampleAPI : BaseAPI
{
private static readonly JsonConverter[] converters = new[] { new RecordCoverter() };
public string APIKey { get; set; }
public ExampleData GetExampleData(/* params here such as string apiKey */) =>
GetTFromRequset<ExampleData>($"examplepath?key={APIKey}", converters);
}
Example data would be something like this:
{
"success":true,
"records":[
{
"Foo":"Bar",
"Data":"Dahta"
}
]
}
So the classes would look like this:
public class RecordConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(IRecord);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public interface IRecord {}
public class ExampleData
{
public bool success { get; set; } = true;
public IRecord[] records { get; set; } = new[] {};
}
public class DataRecord : IRecord
{
public string Foo { get; set; }
public string Data { get; set; }
}
public class FaltyRecord : IRecord
{
public string Bar { get; set; }
public string Dahta { get; set; }
}
The issue that keeps arising that I can't figure out if the objects in "records" is FaltyRecords or DataRecords without doing reader.Read() which would just throw off just being about to put the following into RecordConverter:
if(reader.NextProperties().All(x => DataRecordProps.Contains(x)))
return serializer.Deserialize<DataExample>(reader);
if(reader.NextProperties().All(x => FaltyRecordProps.Contains(x)))
return serializer.Deserialize<FaltyRecord>(reader);
if(...)
return ...;
I know that in XmlReader there's the method GetSubtree() so I can do var propReader = reader.GetSubtree(); then use propReader as much as I want and just do retrun (IRecord[])serializer.Deserialize(reader);. I also see using JObject a lot but I don't see a JObject(reader) method.
Use JObject.Load(reader) method.
var jObj = JObject.Load(reader);
var properties = jObj.Properties();
// code here to find the type
return jObj.ToObject(type);
I create a class for define my request, I don't get the accepted JSON string
I define this object:
public class Request
{
public Var_Args[] var_args { get; set; }
}
public class Var_Args
{
public object title { get; set; }
public object owner { get; set; }
}
when I convert it to json, I get the following string:
{"requests":[{"var_args":[{"title":"Test","owner":"skaner"}]}]}
how can I define the class, for get the accepted json string:
{"requests":[{"var_args":[{"title":"Test"},{"owner":"skaner"}]}]}
You can write a custom JSON converter that can serialize every property of an object (of a known type) into a different JSON object.
public class PropertyAsObjectConverter : JsonConverter
{
private readonly Type[] _types;
public PropertyAsObjectConverter(params Type[] types)
{
_types = types;
}
public override bool CanConvert(Type objectType)
{
return _types.Any(t => t == objectType);
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var properties = value.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);
foreach(var property in properties)
{
var name = property.Name;
var attrs = property.GetCustomAttributes(typeof(JsonPropertyAttribute));
if(attrs != null)
{
if (attrs.FirstOrDefault() is JsonPropertyAttribute attr)
name = attr.PropertyName;
}
writer.WriteStartObject();
writer.WritePropertyName(name);
serializer.Serialize(writer, property.GetValue(value));
writer.WriteEndObject();
}
}
}
This implements only the serialization, but you can extend it to support deserialization too. You can also extend it to serialize fields should you need that.
You can then define your classes as follows. Notice that I am using JsonPropertyAttribute here to specify the name in the serialized JSON.
public class Content
{
[JsonProperty("requests")]
public Request Value { get; set; }
}
public class Request
{
[JsonProperty("var_args")]
public VarArgs[] Arguments { get; set; }
}
public class VarArgs
{
[JsonProperty("title")]
public object Title { get; set; }
[JsonProperty("owner")]
public object Owner { get; set; }
}
This is how you can use it:
static void Main(string[] args)
{
var request = new Content()
{
Value = new Request()
{
Arguments = new VarArgs[]
{
new VarArgs()
{
Title = "Test",
Owner = "Skaner",
}
}
}
};
var text = JsonConvert.SerializeObject(
request,
Formatting.None,
new PropertyAsObjectConverter(typeof(VarArgs)));
Console.WriteLine(text);
}
The output for this sample is the one you expect:
{"requests":{"var_args":[{"title":"Test"},{"owner":"Skaner"}]}}
You could use a custom JsonConverter like the below.
It takes the Var_Args object and splits it in two different JObject which correspond to two different JSON objects.
public class VarArgsConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var obj = (JObject)JToken.FromObject(value);
var objTitle = new JObject();
objTitle.Add("title", obj.GetValue("title"));
var objOwner = new JObject();
objOwner.Add("owner", obj.GetValue("owner"));
objTitle.WriteTo(writer);
objOwner.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Var_Args);
}
}
public class Wrapper
{
[JsonProperty("requests")]
public Request Requests { get; set; }
}
public class Request
{
public Var_Args[] var_args { get; set; }
}
public class Var_Args
{
public object title { get; set; }
public object owner { get; set; }
}
Then use it:
var wrapper = new Wrapper();
var request = new Request();
request.var_args = new Var_Args[] {
new Var_Args(){ title = "Test", owner = "skaner" },
new Var_Args(){ title = "Test2", owner = "skaner2" }
};
wrapper.Requests = request;
var serialized = JsonConvert.SerializeObject(wrapper, new VarArgsConverter());
Output
{"requests":{"var_args":[{"title":"Test"},{"owner":"skaner"},{"title":"Test2"},{"owner":"skaner2"}]}}
Note: I'm using the Wrapper class just to produce the requested JSON.
If you don't want to specify the converter each time, you can register your converter globally. Please see this answer which explains how you can do that. So, the serializer will use your custom JsonConverter every time you try to serialize a Var_Args object.
If you register the JsonConvert globally you can use:
var serialized = JsonConvert.SerializeObject(wrapper);
You can use System.Reflection to redefine Var_Args as an implementation of the IEnumerable<Dictionary<string,object>> interface by adding two methods to the class:
public class Var_Args : IEnumerable<Dictionary<string,object>>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<Dictionary<string,object>> GetEnumerator()
{
var Properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var Property in Properties)
{
var Entry = new Dictionary<string,object>();
Entry.Add(Property.Name, Property.GetValue(this));
yield return Entry;
}
}
public object title { get; set; }
public object owner { get; set; }
}
While Reflection may be regarded as slow, there is a technique you can use to statically compile an IEnumerable at runtime so that the reflection only occurs once for the definition of the class, like this:
public class Var_Args : IEnumerable<Dictionary<string,object>>
{
private struct PropertyList<T>
{
public static readonly List<Func<T,Dictionary<string,object>>> PropertyGetters;
static PropertyList()
{
PropertyGetters = new List<Func<T,Dictionary<string,object>>>();
var Properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var Property in Properties)
{
var Args = new [] { Expression.Parameter(typeof(T)) };
var Key = Property.Name;
var Value = Expression.Property(Args[0], Property);
Func<T,object> Get = Expression.Lambda<Func<T,object>>(Value, Args).Compile();
PropertyGetters.Add(obj =>
{
var entry = new Dictionary<string,object>();
entry.Add(Key, Get(obj));
return entry;
});
}
}
}
protected static IEnumerable<Dictionary<string,object>> GetPropertiesAsEntries<T>(T obj)
{
return PropertyList<T>.PropertyGetters.Select(f => f(obj));
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<Dictionary<string,object>> GetEnumerator()
{
return GetPropertiesAsEntries(this).GetEnumerator();
}
public object title { get; set; }
public object owner { get; set; }
}
I have two JSON files (that I can't change the format for) in the following format:
Main file -
[
{
"Name":"XYZ",
"UnitReferenceId":1
},
{
"Name":"ABC",
"UnitReferenceId":2
}
]
The lookup/reference JSON file -
[
{
"UnitReferenceId":1,
"Units":[
{
"Unit":"mg",
"Scale":1
},
{
"Unit":"gm",
"Scale":1000
},
{
"Unit":"kg",
"Scale":1000000
}
]
},
{
"UnitReferenceId":2,
"Units":[
{
"Unit":"mm",
"Scale":1
},
{
"Unit":"m",
"Scale":1000
},
{
"Unit":"km",
"Scale":1000000
}
]
}
]
How would I go about deserializing that into C# classes using Newtonsoft JSON into something like:
public class Widget
{
public string Name {get; set;}
public UnitReference UnitReference { get; set; }
}
public class UnitReference
{
public long UnitReferenceId { get; set; }
public List<Unit> Units { get; set; }
}
public class Unit
{
[JsonProperty("Unit")]
public string UnitValue { get; set; }
public long Scale { get; set; }
}
Any help would be greatly appreciated!
You can do this by reading your two JSON files as follows:
First read the lookup/reference JSON file for UnitReference as a List<UnitReference>, then convert to a Dictionary<long, UnitReference> lookup table.
Next, read the main file using a custom JsonConverter for Widget that is passed the Dictionary<long, UnitReference> lookup table and can translate between UnitReferenceId and UnitReference during reading and writing.
Thus your classes would look like the following:
public class UnitReference
{
readonly long unitReferenceId;
public UnitReference(long unitReferenceId)
{
this.unitReferenceId = unitReferenceId;
}
public long UnitReferenceId { get { return unitReferenceId; } }
public List<Unit> Units { get; set; }
}
public class Unit
{
[JsonProperty("Unit")]
public string UnitValue { get; set; }
public long Scale { get; set; }
}
public class Widget
{
public string Name { get; set; }
public UnitReference UnitReference { get; set; }
}
(My only modification was to make UnitReferenceId be read-only so that it safely could be used as a dictionary key.)
Then, define the following converter:
public class WidgetConverter : CustomPropertyConverterBase<Widget>
{
readonly IDictionary<long, UnitReference> units;
public WidgetConverter(IDictionary<long, UnitReference> units)
{
this.units = units;
}
protected override void ReadCustomProperties(JObject obj, Widget value, JsonSerializer serializer)
{
var id = (long?)obj.GetValue("UnitReferenceId", StringComparison.OrdinalIgnoreCase);
if (id != null)
value.UnitReference = units[id.Value];
}
protected override bool ShouldSerialize(JsonProperty property, object value)
{
if (property.UnderlyingName == nameof(Widget.UnitReference))
return false;
return base.ShouldSerialize(property, value);
}
protected override void WriteCustomProperties(JsonWriter writer, Widget value, JsonSerializer serializer)
{
if (value.UnitReference != null)
{
writer.WritePropertyName("UnitReferenceId");
writer.WriteValue(value.UnitReference.UnitReferenceId);
}
}
}
public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jObj = JObject.Load(reader);
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
var value = existingValue as T ?? (T)contract.DefaultCreator();
ReadCustomProperties(jObj, value, serializer);
// Populate the remaining properties.
using (var subReader = jObj.CreateReader())
{
serializer.Populate(subReader, value);
}
return value;
}
protected abstract void ReadCustomProperties(JObject obj, T value, JsonSerializer serializer);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
writer.WriteStartObject();
foreach (var property in contract.Properties.Where(p => ShouldSerialize(p, value)))
{
var propertyValue = property.ValueProvider.GetValue(value);
if (propertyValue == null && serializer.NullValueHandling == NullValueHandling.Ignore)
continue;
writer.WritePropertyName(property.PropertyName);
serializer.Serialize(writer, propertyValue);
}
WriteCustomProperties(writer, (T)value, serializer);
writer.WriteEndObject();
}
protected virtual bool ShouldSerialize(JsonProperty property, object value)
{
return property.Readable && !property.Ignored && (property.ShouldSerialize == null || property.ShouldSerialize(value));
}
protected abstract void WriteCustomProperties(JsonWriter writer, T value, JsonSerializer serializer);
}
And deserialize as follows:
var units = JsonConvert.DeserializeObject<List<UnitReference>>(unitsJsonString)
.ToDictionary(u => u.UnitReferenceId);
var settings = new JsonSerializerSettings
{
Converters = { new WidgetConverter(units) },
};
var widgets = JsonConvert.DeserializeObject<List<Widget>>(widgetsJsonString, settings);
Notes:
Here I am deserializing from JSON strings for demo purposes, but you can deserialize directly from your file(s) as shown in Deserialize JSON from a file.
The base class CustomPropertyConverterBase<T> for WidgetConverter automatically reads and writes all properties for the object being (de)serialized. WidgetConverter then overrides this behavior for the UnitReference property only, avoiding the necessity to manually serialize all the remaining properties of Widget.
Sample fiddle.
I use json2csharp for creating my classes quickly. If you have to implement it in code, see JSON C# Class Generator Project.
Say I have some Json that will come in a packet like this:
{
"LinkType1": "google",
"LinkUrl1": "https://plus.google.com/test",
"LinkShow1": 1,
"LinkType2": "facebook",
"LinkUrl2": "https://www.facebook.com/test",
"LinkShow2": 0,
"LinkType3": "linkedin",
"LinkUrl3": "http://www.linkedin.com/test",
"LinkShow3": 1,
"count": 3,
"errorCode": 0,
"errorMessage": "Success"
}
Notice how everything comes back as the same property, but with an index on it?
I would love to be able to deserialize that data as though it was an array instead of single properties. What would be the best method for deserializing this into the classes below? I'm using the Newtonsoft Json library for serialization, so a solution using that would be preferred.
public class LinksResult
{
public List<LinkData> Links { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("errorCode")]
public int ErrorCode { get; set; }
[JsonProperty("errorMessage")]
public string ErrorMessage { get; set; }
}
public class LinkData
{
public string LinkType { get; set; }
public string LinkUrl { get; set; }
public bool LinkShow { get; set; }
}
You can use a custom JsonConverter to deserialize the JSON data into the structure that you want. Here is what the code for the converter might look like.
class LinksResultConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(LinksResult));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
LinksResult result = new LinksResult();
result.Count = (int)obj["count"];
result.ErrorCode = (int)obj["errorCode"];
result.ErrorMessage = (string)obj["errorMessage"];
result.Links = new List<LinkData>();
for (int i = 1; i <= result.Count; i++)
{
string index = i.ToString();
LinkData link = new LinkData();
link.LinkType = (string)obj["LinkType" + index];
link.LinkUrl = (string)obj["LinkUrl" + index];
link.LinkShow = (int)obj["LinkShow" + index] == 1;
result.Links.Add(link);
}
return result;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use the converter, just add a [JsonConverter] attribute to your LinksResult class as shown below. (Note that you don't need the [JsonProperty] attributes with this approach, since the mapping between JSON property names and the actual class members is handled directly by the converter.)
[JsonConverter(typeof(LinksResultConverter))]
public class LinksResult
{
public List<LinkData> Links { get; set; }
public int Count { get; set; }
public int ErrorCode { get; set; }
public string ErrorMessage { get; set; }
}
Then, you can deserialize like this:
LinksResult result = JsonConvert.DeserializeObject<LinksResult>(json);
Fiddle: https://dotnetfiddle.net/56b34H
Brian's answer was very good and it got me 80% of the way to where I wanted to be. However it's not a very good implementation to use over and over again if this sort of pattern happens on many different objects.
I made something more generic. An interface that a "Page" would have.
public interface IPage<TItem>
{
int Count { get; set; }
List<TItem> PageItems { get; set; }
}
Then the Page converter itself.
public class PageConverter<TPage, TItem> : JsonConverter
where TPage : IPage<TItem>, new()
where TItem : new()
{
private readonly Regex _numberPostfixRegex = new Regex(#"\d+$");
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(TPage));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = serializer.Deserialize<JObject>(reader);
var page = new TPage();
serializer.Populate(obj.CreateReader(), page); //Loads everything that isn't a part of the items.
page.PageItems = new List<TItem>();
for (int i = 1; i <= page.Count; i++)
{
string index = i.ToString();
//Find all properties that have a number at the end, then any of those that are the same number as the current index.
//Put those in a new JObject.
var jsonItem = new JObject();
foreach (var prop in obj.Properties().Where(p => _numberPostfixRegex.Match(p.Name).Value == index))
{
jsonItem[_numberPostfixRegex.Replace(prop.Name, "")] = prop.Value;
}
//Deserialize and add to the list.
TItem item = jsonItem.ToObject<TItem>(serializer);
page.PageItems.Add(item);
}
return page;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
So then all that's needed is to implement it on the links result:
[JsonConverter(typeof(PageConverter<LinksResult, LinkData>))]
public class LinksResult : IPage<LinkData>
{
public int Count { get; set; }
public List<LinkData> PageItems { get; set; }
}
I figured out you can control the serialization of capitalization with JsonSerializerSettings, so best leave that detail up to the chosen serializer, not my converter.
Fiddle here: https://dotnetfiddle.net/7KhwYY
Here is similar solution you may apply. See Serialize json to an object with catch all dictionary property The answer by David Hoerster.
I want to deserialize a complex and let's say not well constructed json. That code that I wrote doesn't deserialize the object, the MovieInfo property is null. You can find the example json in the code. I want to avoid using JObject.Parse and dynamic objects. What am I missing here?
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ComplexJsonExample
{
class Program
{
static void Main(string[] args)
{
string jsonInText = #"
{
""movies"" : [
{
""Harry Potter"" : [
{ ""rating"": ""great""},
{ ""rating"": ""horrible""}
]
},
{
""Guardians of the galaxy"" : [
{ ""rating"": ""cool""},
{ ""rating"": ""awesome""}
]
}
]
}
";
var movieList = JsonConvert.DeserializeObject<MovieList>(jsonInText);
}
}
public class MovieList
{
[JsonProperty("movies")]
public IList<Movie> Movies { get; set; }
}
public class Movie
{
IDictionary<string, IList<MovieRating>> MovieInfo { get; set; }
}
public class MovieRating
{
[JsonProperty("rating")]
public string Rating { get; set; }
}
}
It's a bit ugly, but you can do it like this:
class MovieList
{
[JsonProperty("movies")]
public Movie[] Movies { get; set; }
}
class Movie : Dictionary<string, MovieRating[]>
{
}
class MovieRating
{
[JsonProperty("rating")]
public string Rating { get; set; }
}
It's weird that the movie is a dictionary with only one key (its title), but it matches the JSON structure. You can always map it to something more sensible after deserialization.
I consider this a bit of a hack, but it works, and deserializes your json string into the format you required:
class MovieConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Movie);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var movie = new Movie(){
MovieInfo = new Dictionary<string,IList<MovieRating>>()
};
while (reader.Read() && reader.Value != null)
{
var name = (string)reader.Value;
reader.Read();
var ratings = ((JArray)serializer.Deserialize(reader)).Values<string>("rating");
movie.MovieInfo.Add(name, ratings.Select(r => new MovieRating(){ Rating = r}).ToList());
}
return movie;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
I did have to make two changes to your original objects, first I made the accessor for MovieInfo public so I could access it, and second to add the JsonConverterAttribute:
[JsonConverter(typeof(MovieConverter))]
public class Movie
{
public IDictionary<string, IList<MovieRating>> MovieInfo { get; set; }
}