How to use custom reference resolving with JSON.NET

前端 未结 2 1591
攒了一身酷
攒了一身酷 2020-12-29 11:21

I have the following JSON:

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


        
相关标签:
2条回答
  • 2020-12-29 11:39

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-29 11:45

    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());
            }
    }
    

    Updated answer :

    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));
            }
    }
    
    0 讨论(0)
提交回复
热议问题