I have the following JSON:
{
\"id\" : \"2\"
\"categoryId\" : \"35\"
\"type\" : \"item\"
\"name\" : \"hamburger\"
}
{
You can specify a custom IRefenceResover in your JsonSerializerSettings:
JsonSerializerSettings settings = new JsonSerializerSettings ();
settings.ReferenceResolver = new IDReferenceResolver ();
There is an excellent implementation example of IDReferenceResolver for objects with a Guid id property. The reference string is now the object's id, which is similar to your use case except that your are using int instead of Guid types for your id property.
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Tests.TestObjects
{
public class IdReferenceResolver : IReferenceResolver
{
private readonly IDictionary<Guid, PersonReference> _people = new Dictionary<Guid, PersonReference>();
public object ResolveReference(object context, string reference)
{
Guid id = new Guid(reference);
PersonReference p;
_people.TryGetValue(id, out p);
return p;
}
public string GetReference(object context, object value)
{
PersonReference p = (PersonReference)value;
_people[p.Id] = p;
return p.Id.ToString();
}
public bool IsReferenced(object context, object value)
{
PersonReference p = (PersonReference)value;
return _people.ContainsKey(p.Id);
}
public void AddReference(object context, string reference, object value)
{
Guid id = new Guid(reference);
_people[id] = (PersonReference)value;
}
}
}
Use CustomCreationConverter<T>
as JsonConverter and override both Create
and ReadJson
method.
class ItemConverter : CustomCreationConverter<Item> {
public override Item Create(Type objectType)
{
return new Item();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
int categoryId = jObject["categoryId"].ToObject<int>();
Category category = Program.Repository.GetCategoryById(categoryId);
Item result = (Item)base.ReadJson(jObject.CreateReader(), objectType, existingValue, serializer);
result.Category = category;
return result;
}
}
class Item {
[JsonProperty("itemName")]
public string ItemName { get; set; }
public Category Category { get; set; }
// other properties.
}
class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
// other properties.
}
class MockCategoryRepository {
IList<Category> _repository;
public MockCategoryRepository()
{
_repository = new List<Category>();
_repository.Add(new Category() { CategoryId = 1, Name = "Drink" });
_repository.Add(new Category() { CategoryId = 35, Name = "Food" });
_repository.Add(new Category() { CategoryId = 70, Name = "Fruit" });
}
public Category GetCategoryById(int id)
{
return _repository.Where(x => x.CategoryId == id).SingleOrDefault();
}
}
class Program {
public static MockCategoryRepository Repository { get; private set; }
static void Main(string[] args)
{
Repository = new MockCategoryRepository(); // initialize mock repository
// sample : json contains two items in an array.
string jsonString = @"
[
{ ""categoryId"":""35"", ""itemName"":""Item A"" },
{ ""categoryId"":""70"", ""itemName"":""Item B"" },
]";
List<Item> items = JsonConvert.DeserializeObject<List<Item>>(jsonString, new ItemConverter());
}
}
Solution for condition where Category
object information is fetched from the same json string.
class ItemConverter : CustomCreationConverter<Item> {
readonly IEnumerable<Category> _repository;
public ItemConverter(IEnumerable<Category> categories)
{
_repository = categories;
}
public override Item Create(Type objectType)
{
return new Item();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
int categoryId = jObject["categoryId"].ToObject<int>();
Category category = _repository.Where(x => x.CategoryId == categoryId).SingleOrDefault();
Item result = (Item)base.ReadJson(jObject.CreateReader(), objectType, existingValue, serializer);
result.Category = category;
return result;
}
}
class Item {
[JsonProperty("name")]
public string Name { get; set; }
public Category Category { get; set; }
// other properties.
}
class Category {
[JsonProperty("id")]
public int CategoryId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
// other properties.
}
class Program {
static void Main(string[] args)
{
// sample : json contains items and/or categories in an array.
string jsonString = @"
[
{
""id"" : ""2"",
""categoryId"" : ""35"",
""type"" : ""item"",
""name"" : ""hamburger""
},
{
""id"" : ""35"",
""type"" : ""category"",
""name"" : ""drinks""
}
]";
JArray jsonArray = JArray.Parse(jsonString);
// Separate between category and item data.
IEnumerable<JToken> jsonCategories = jsonArray.Where(x => x["type"].ToObject<string>() == "category");
IEnumerable<JToken> jsonItems = jsonArray.Where(x => x["type"].ToObject<string>() == "item");
// Create list of category from jsonCategories.
IEnumerable<Category> categories = jsonCategories.Select(x => x.ToObject<Category>());
// Settings for jsonItems deserialization.
JsonSerializerSettings itemDeserializerSettings = new JsonSerializerSettings();
itemDeserializerSettings.Converters.Add(new ItemConverter(categories));
JsonSerializer itemDeserializer = JsonSerializer.Create(itemDeserializerSettings);
// Create list of item from jsonItems.
IEnumerable<Item> items = jsonItems.Select(x => x.ToObject<Item>(itemDeserializer));
}
}