如何使用JSON.NET自定义引用解析

时间:2012-02-11 04:59:11

标签: c# json json.net

我有以下JSON:

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

我希望将它与此对象匹配:

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

Category属于Entity类型,其中包含string Id属性。我希望JSON反序列化器创建的“35”对象映射到Category中的Item属性。

根据to the documentation,我应该使用IReferenceResolver。我如何实现此接口并将其挂钩到JSON.NET框架中?

2 个答案:

答案 0 :(得分:11)

您可以在JsonSerializerSettings中指定自定义IRefenceResover:

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

对于具有 Guid id 属性的对象,有一个很好的IDReferenceResolver实现示例。引用字符串现在是对象的 id ,除了您使用 int 而不是 Guid 之外,它类似于您的用例你的id属性的类型。

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

答案 1 :(得分:1)

使用CustomCreationConverter<T>作为JsonConverter并覆盖CreateReadJson方法。

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

更新回答:

从同一个json字符串中获取Category对象信息的条件的解决方案。

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