Come utilizzare la risoluzione dei riferimenti personalizzati con JSON.NET

Ho il seguente JSON:

{ "id" : "2" "categoryId" : "35" "type" : "item" "name" : "hamburger" } { "id" : "35" "type" : "category" "name" : "drinks" } 

E voglio abbinarlo a questo object:

 public class Item { [JsonProperty(PropertyName = "categoryId")] public Category Category { get; set; } } 

Category è di tipo Entity che ha una proprietà Id string cui posso accedere. Voglio che l’object “35” creato dal deserializzatore JSON sia mappato alla proprietà Category nell’elemento.

Secondo la documentazione , dovrei usare un IReferenceResolver . Come implementare questa interfaccia e collegarla al framework JSON.NET?

Puoi specificare un IRefenceResover personalizzato in JsonSerializerSettings:

 JsonSerializerSettings settings = new JsonSerializerSettings (); settings.ReferenceResolver = new IDReferenceResolver (); 

Esiste un eccellente esempio di implementazione di IDReferenceResolver per oggetti con una proprietà id Guid . La stringa di riferimento è ora l’ id dell’object, che è simile al tuo caso d’uso, tranne che stai usando int invece dei tipi Guid per la tua proprietà id.

 using System; using System.Collections.Generic; using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Tests.TestObjects { public class IdReferenceResolver : IReferenceResolver { private readonly IDictionary _people = new Dictionary(); 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; } } } 

Utilizzare CustomCreationConverter come JsonConverter e sovrascrivere sia il metodo Create che ReadJson .

 class ItemConverter : CustomCreationConverter { 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(); 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 _repository; public MockCategoryRepository() { _repository = new List(); _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 items = JsonConvert.DeserializeObject>(jsonString, new ItemConverter()); } } 

Risposta aggiornata:

Soluzione per condizione in cui le informazioni dell’object Category vengono recuperate dalla stessa stringa json.

 class ItemConverter : CustomCreationConverter { readonly IEnumerable _repository; public ItemConverter(IEnumerable 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(); 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 jsonCategories = jsonArray.Where(x => x["type"].ToObject() == "category"); IEnumerable jsonItems = jsonArray.Where(x => x["type"].ToObject() == "item"); // Create list of category from jsonCategories. IEnumerable categories = jsonCategories.Select(x => x.ToObject()); // 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 items = jsonItems.Select(x => x.ToObject(itemDeserializer)); } }