如何让我JSON.NET忽略对象关系 [英] How Do I Make JSON.NET Ignore Object Relationships

查看:246
本文介绍了如何让我JSON.NET忽略对象关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的实体框架项目。我想序列一堆实体类的实例。我已经绑定在一起到这些容器类:

I'm working on an Entity Framework project. I want to serialize a bunch of entity class instances. I've bound these together into a container class:

public class Pseudocontext
{
    public List<Widget> widgets;
    public List<Thing> things;

等耳熟能详的乐曲......正是这一类,我试图序列化的一个实例。我想是的JSON.NET序列化每个实体类实例的成员,实际上是基础数据库中的列。我不希望它甚至试图序列化对象引用。特别是,我的实体类有虚成员允许我写C#code的导航我的所有实体间的关系,而不必担心实际键值,连接,等,我想JSON.NET忽略相关零件我的实体类。

Etcetera... it is an instance of this class that I'm attempting to serialize. What I want is for JSON.NET to serialize the members of each entity class instance that are actually columns in the underlying database. I do not want it to even attempt to serialize object references. In particular, my entity classes have virtual members that allow me to write C# code that navigates all my inter-entity relationships without worrying about actual key values, joins, etc., and I want JSON.NET to ignore the associated parts of my entity classes.

从表面上看,似乎有,它正是我谈论的是一个JSON.NET配置选项:

On the surface, there seems to be a JSON.NET configuration option that does exactly what I'm talking about:

        JsonSerializer serializer = new JsonSerializer();
        serializer.PreserveReferencesHandling = PreserveReferencesHandling.None; 

不幸的是,JSON.NET似乎被忽略了上面的第二条语句。

Unfortunately, JSON.NET seems to be ignoring the second statement above.

我居然发现了一个网页( HTTP://json.$c$cplex.com/workitem/24608 ),其中有人提出了同样的问题,以詹姆斯·牛顿 - 国王本人和他的反应的注意力(的全部内容)是写一个自定义的合同解析器。

I actually found a web page (http://json.codeplex.com/workitem/24608) where someone else brought the same issue to the attention of James Newton-King himself, and his response (in its entirety) was "Write a custom contract resolver."

由于不充分的,因为我觉得这种反应是,我一直在试图遵循的指导。我也非常希望能够与它一起包含直接在列表写了一个合同解析器是无视一切,除了基本类型,字符串,日期时间的对象,和我自己的Pseudocontext类。如果某人具有一些至少类似于一个例子,它可能是我所需要的。这是我想出了我自己的:

As inadequate as I find that response to be, I have been attempting to follow its guidance. I would very much like to be able to write a "contract resolver" that ignored everything except primitive types, strings, DateTime objects, and my own Pseudocontext class along with the Lists it contains directly. If someone has an example of something that at least resembles that, it might be all I need. This is what I came up with on my own:

public class WhatDecadeIsItAgain : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        JsonContract contract = base.CreateContract(objectType);
        if (objectType.IsPrimitive || objectType == typeof(DateTime) || objectType == typeof(string) 
            || objectType == typeof(Pseudocontext) || objectType.Name.Contains("List"))
        {   
            contract.Converter = base.CreateContract(objectType).Converter;
        }
        else
        {
            contract.Converter = myDefaultConverter;
        }            
        return contract;
    }
    private static GeeThisSureTakesALotOfClassesConverter myDefaultConverter = new GeeThisSureTakesALotOfClassesConverter();
}
public class GeeThisSureTakesALotOfClassesConverter : Newtonsoft.Json.Converters.CustomCreationConverter<object>
{
     public override object Create(Type objectType)
    {
        return null;
    }
}

当我尝试使用上面的(通过设置serializer.ContractResolver到WhatDecadeIsItAgain之前序列化的一个实例),我得到的序列化时内存溢出错误,表明JSON.NET遇到了参考循环,永远不会终止(尽管我努力使JSON.NET的忽略的对象引用)。

When I attempt to use the above (by setting serializer.ContractResolver to an instance of WhatDecadeIsItAgain prior to serialization), I get OutOfMemory errors during serialization that indicate that JSON.NET is encountering reference loops that never terminate (in spite of my efforts to make JSON.NET just ignore object references).

我觉得我的定制合同解析器可能是错误的。如上图所示,它是建立在premise,我应该回到默认的合同因为我确实想序列化的类型,和一个合同,简单地返回空为所有其他类型。

I feel like my "custom contract resolver" may be wrong. As shown above, it's built around the premise that I should return the default "contract" for the types I do want to serialize, and a "contract" that simply returns "null" for all other types.

我不知道这些假设是如何正确的,不过,这并不容易分辨。该JSON.NET的设计是非常基础上实现继承,方法重载等;我没有太多的O​​OP的家伙,我觉得那样的设计是pretty的模糊。有没有一个,我可以实现定制合同解决程序的界面,的Visual Studio 2012将能够很快存根出所需的方法,和我想象我有一点麻烦填充存根与现实逻辑。我有没有问题的文字,例如,返回true如果我想序列化,否则所提供的类型的对象和假的方法。也许我失去了一些东西,但我没有找到这样的方法覆盖,也没有我能找到的假想界面(ICustomContractResolver?)那会告诉我什么,我其实应该做的最后$ C上述$ C片段插入。

I have no idea how correct these assumptions are, though, and it's not easy to tell. The JSON.NET design is very much based on implementation inheritance, method overriding, etc.; I'm not much of an OOP guy, and I find that sort of design to be pretty obscure. Were there a "custom contract resolver" interface that I could implement, Visual Studio 2012 would be able to stub out the required methods very quickly, and I imagine I'd have little trouble filling the stubs in with real logic. I'd have no problem writing, for example, a method that returns "true" if I want to serialize an object of a supplied type and "false" otherwise. Perhaps I'm missing something, but I've found no such method to override, nor have I been able to find the hypothetical interface (ICustomContractResolver ?) that would tell me what I'm actually supposed to be doing in the last code snippet inserted above.

另外,我认识到,有JSON.NET属性([JsonIgnore]?),旨在应对这样的情况。我真的不能使用这种方法,因为我使用的模式先。除非我决定要撕了我的整个项目的建筑,我的实体类将被自动生成的,并且他们将不包含JsonIgnore属性,我也不觉得舒服编辑自动化类以包含这些属性。

Also, I realize that there are JSON.NET attributes ([JsonIgnore]?) that are designed to deal with situations like this. I can't really use that approach, since I'm using "model first". Unless I decide to tear up my entire project architecture, my entity classes will be automatically generated, and they will not contain JsonIgnore attributes, nor do I feel comfortable editing the automated classes to contain these attributes.

顺便说一下,一会儿我的没有的有事情成立了序列化对象引用,而我只是忽略所有多余的$ REF和$ ID数据JSON.NET正在恢复在它的序列化输出。我已经放弃了这样的方法至少在目前,因为(陡然)序列开始服用过多的时间量(〜45分钟搞定〜JSON的5MB)。

Incidentally, for a while I did have things set up to serialize object references, and I was just ignoring all the superfluous "$ref" and "$id" data that JSON.NET was returning in its serialization output. I've abandoned that approach for the moment at least, because (rather suddenly) serialization started taking an inordinate amount of time (~45 minutes to get ~5MB of JSON).

我一直没能配合性能突然变回具体的,我做了什么。如果有的话,数据在我的数据库中的体积下,现在比当序列化实际上是在完成合理的时间。不过,我会很乐意用一回的原状的(中,我只是有忽视$ REF,$ ID等),如果能实现

I haven't been able to tie that sudden change in performance back to anything specific that I did. If anything, the volume of data in my database is lower now than it was when serialization was actually completing in reasonable time. But I'd be more than happy with a return to the status quo ante (in which I was just having to ignore "$ref", "$id", etc.) if that could be achieved.

在这一点上,我也愿意使用一些其他的JSON库,或不同的策略完全的前景。我觉得我可以只使用StringBuilder的,的System.Reflection等,并提出用我自己的,自制的解决方案......但不JSON.NET应该能够轻松地处理这样的事情pretty的? ?

At this point, I'm also open to the prospect of using some other JSON library, or a different strategy altogether. I feel like I could just use StringBuilder, System.Reflection, etc. and come of with my own, homemade solution... but isn't JSON.NET supposed to be able to handle this sort of thing pretty easily??

推荐答案

首先,参照loops--的 preserveReferencesHandling 设置控制解决你的问题是否的Json净发出的$ id $ REF 来追踪对象间引用。如果你有这样的设置为和你的对象图中包含循环,那么你还需要设置 ReferenceLoopHandling 忽略来prevent错误。

First, to address your issues with reference loops-- The PreserveReferencesHandling setting controls whether Json.Net emits $id and $ref to track inter-object references. If you have this set to None and your object graph contains loops, then you will also need to set ReferenceLoopHandling to Ignore to prevent errors.

现在,让Json.Net完全忽略所有的对象引用,只有序列化的原始特性(除非在你的 Pseudocontext 类课程),你需要一个定制合同解析器,如你所说。不过别担心,这不是很难,因为你的想法。解析器必须注入 ShouldSerialize 方法,每个属性来控制属性是否应该被包含在输出的能力。所以,你需要做的是从默认的派生解析器,然后重写 CreateProperty 方法,使得它集 ShouldSerialize 适当。 (您不需要自定义 JsonConverter 在这里,虽然可以解决这个问题,这种方法尽管有相当多的code)

Now, to get Json.Net to ignore all object references altogether and only serialize primitive properties (except in your Pseudocontext class of course), you do need a custom Contract Resolver, as you suggested. But don't worry, it is not as hard as you think. The resolver has the capability to inject a ShouldSerialize method for each property to control whether or not that property should be included in the output. So, all you need to do is derive your resolver from the default one, then override the CreateProperty method such that it sets ShouldSerialize appropriately. (You do not need a custom JsonConverter here, although it is possible to solve this problem with that approach albeit with quite a bit more code.)

下面是$ C $下的解析:

Here is the code for the resolver:

class CustomResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        if (prop.DeclaringType != typeof(PseudoContext) && 
            prop.PropertyType.IsClass && 
            prop.PropertyType != typeof(string))
        {
            prop.ShouldSerialize = obj => false;
        }

        return prop;
    }
}

下面是一个完整的演示显示了正在运行的解析器。

Here is a full demo showing the resolver in action.

class Program
{
    static void Main(string[] args)
    {
        // Set up some dummy data complete with reference loops
        Thing t1 = new Thing { Id = 1, Name = "Flim" };
        Thing t2 = new Thing { Id = 2, Name = "Flam" };

        Widget w1 = new Widget
        {
            Id = 5,
            Name = "Hammer",
            IsActive = true,
            Price = 13.99M,
            Created = new DateTime(2013, 12, 29, 8, 16, 3),
            Color = Color.Red,
        };
        w1.RelatedThings = new List<Thing> { t2 };
        t2.RelatedWidgets = new List<Widget> { w1 };

        Widget w2 = new Widget
        {
            Id = 6,
            Name = "Drill",
            IsActive = true,
            Price = 45.89M,
            Created = new DateTime(2014, 1, 22, 2, 29, 35),
            Color = Color.Blue,
        };
        w2.RelatedThings = new List<Thing> { t1 };
        t1.RelatedWidgets = new List<Widget> { w2 };

        // Here is the container class we wish to serialize
        PseudoContext pc = new PseudoContext
        {
            Things = new List<Thing> { t1, t2 },
            Widgets = new List<Widget> { w1, w2 }
        };

        // Serializer settings
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.ContractResolver = new CustomResolver();
        settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
        settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        settings.Formatting = Formatting.Indented;

        // Do the serialization and output to the console
        string json = JsonConvert.SerializeObject(pc, settings);
        Console.WriteLine(json);
    }

    class PseudoContext
    {
        public List<Thing> Things { get; set; }
        public List<Widget> Widgets { get; set; }
    }

    class Thing
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Widget> RelatedWidgets { get; set; }
    }

    class Widget
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool IsActive { get; set; }
        public decimal Price { get; set; }
        public DateTime Created { get; set; }
        public Color Color { get; set; }
        public List<Thing> RelatedThings { get; set; }
    }

    enum Color { Red, White, Blue }
}

输出:

{
  "Things": [
    {
      "Id": 1,
      "Name": "Flim"
    },
    {
      "Id": 2,
      "Name": "Flam"
    }
  ],
  "Widgets": [
    {
      "Id": 5,
      "Name": "Hammer",
      "IsActive": true,
      "Price": 13.99,
      "Created": "2013-12-29T08:16:03",
      "Color": 0
    },
    {
      "Id": 6,
      "Name": "Drill",
      "IsActive": true,
      "Price": 45.89,
      "Created": "2014-01-22T02:29:35",
      "Color": 2
    }
  ]
}

希望这是什么,你要找的球场。

Hope this is in the ballpark of what you were looking for.

这篇关于如何让我JSON.NET忽略对象关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆