从定制JsonConverter在Json.Net JsonSerializer自参考环路(网页API) [英] Self referencing loop in Json.Net JsonSerializer from custom JsonConverter (Web API)

查看:178
本文介绍了从定制JsonConverter在Json.Net JsonSerializer自参考环路(网页API)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该项目是一个Asp.Net的Web API Web服务。

The project is an Asp.Net Web API web service.

我有一个类型层次,我需要能够序列化和JSON,所以我采取了code从这个SO:<一href=\"http://stackoverflow.com/questions/8030538/how-to-implement-custom-jsonconverter-in-json-net-to-deserialize-a-list-of-base\">How实现自定义JsonConverter在JSON.NET反序列化基类的List对象,并应用转换器到我的层次结构的基类;像这样(有伪code这里隐藏不相干):

I have a type hierarchy that I need to be able to serialize to and from Json, so I have taken the code from this SO: How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects, and applied the converter to my hierarchy's base class; something like this (there's pseudo-code here to hide irrelevancies):

[JsonConverter(typeof(TheConverter))]
public class BaseType{
  ///note the base of this type here is from the linked SO above
  private class TheConverter : JsonCreationConverter<BaseType>{
    protected override BaseType Create(Type objectType, JObject jObject){
      Type actualType = GetTypeFromjObject(jObject); /*method elided*/
      return (BaseType)Activator.CreateInstance(actualType);
    }
  }
}

public class RootType {
  public BaseType BaseTypeMember { get; set; }
}

public class DerivedType : BaseType {      
}

所以,如果我反序列化 BaseTypeMember A RootType 实例,其等于实例 DerivedType ,那么它将被反序列化回到该类型的实例。

So if I deserialize a RootType instance whose BaseTypeMember was equal to an instance of DerivedType, then it will be deserialized back into an instance of that type.

有关记录,这些JSON对象包含其中包含的虚拟类型名称(而不是完整的.NET类型名),所以我可以同时支持在一个类型'$类型字段JSON的同时准确控制哪些类型的可序列化和反序列化。

For the record, these JSON objects contain a '$type' field which contains virtual type names (not full .Net type names) so I can simultaneously support types in the JSON whilst controlling exactly which types can be serialized and deserialized.

现在这个作品真的很好的反序列化从请求值;但我有一个序列化的问题。如果你看一下链接的SO,确实是从顶部答案链接的Json.Net讨论,你会看到,该基地code我用反序列化周围完全面向;与显示手动创建的序列化它的用法。在 JsonConverter 的实施带来的表本 JsonCreationConverter&LT; T&GT; 简单地抛出一个 NotImplementedException

Now this works really well for deserializing values from the request; but I have an issue with serialization. If you look at the linked SO, and indeed the Json.Net discussion that is linked from the top answer, you'll see that the base code I'm using is entirely geared around deserialization; with examples of its use showing manual creation of the serializer. The JsonConverter implementation brought to the table by this JsonCreationConverter<T> simply throws a NotImplementedException.

现在,因为该Web API使用单一格式的请求的方式,我需要实现在的writeObject 方法'标准'的序列化。

Now, because of the way that Web API uses a single formatter for a request, I need to implement 'standard' serialization in the WriteObject method.

我必须在这一点上强调,在开始我的这部分项目之前,我有所有序列正确的没有错误

I must stress at this point that before embarking on this part of my project I had everything serializing properly without errors.

所以我这样做:

public override void WriteJson(JsonWriter writer, 
  object value, 
  JsonSerializer serializer)
{
  serializer.Serialize(writer, value);
}

但我得到一个 JsonSerializationException 型'DerivedType ,对象,当一个自引用循环检测序列化。再次 - 如果我删除该转换器的属性(禁用我的自定义生成),那么它工作正常...

But I get a JsonSerializationException: Self referencing loop detected with type 'DerivedType', when one of the objects is serialized. Again - if I remove the converter attribute (disabling my custom creation) then it works fine...

我有一种感觉,这意味着我的系列化code实际上再次触发转换器相同的对象,这反过来又再次调用序列化的 - 令人作呕。 确认 - 见我的答案

I have a feeling that this means that my serialization code is actually triggering the converter again on the same object, which in turn calls the serializer again - ad nauseam. Confirmed - see my answer

那么,code的的我在的writeObject 那会做同样的标准系列化的作品写?

So what code should I be writing in WriteObject that'll do the same 'standard' serialization that works?

推荐答案

嗯,这很有趣...

当我在为异常堆栈跟踪更加仔细地看了看,我注意到,该方法 JsonSerializerInternalWriter.SerializeConvertable 在那里两次,其实这也是该方法一关该堆栈的顶部 - 调用 JsonSerializerInternalWriter.CheckForCircularReference - 这又是抛出异常。也有人,但是,打到我自己转换器的方法的来源。

When I looked more closely at the stack trace for the exception, I noticed that the method JsonSerializerInternalWriter.SerializeConvertable was in there twice, indeed it was that method one off the top of the stack - invoking JsonSerializerInternalWriter.CheckForCircularReference - which in turn was throwing the exception. It was also, however, the source of the call to my own converter's Write method.

所以,它似乎是序列化是做:

So it would seem that the serializer was doing:


  • 1)如果对象有一个转换器

    • 1A)如果扔循环引用

    • 1b)中调用转换器的Write方法


    • 2A)使用内部串行

    因此​​,在这种情况下,Json.Net呼唤我的转换器,其又调用Json.Net串行器,然后吹了,因为它认为它已经序列化传递给它的对象!

    So, in this case, the Json.Net is calling my converter which in turn is calling the Json.Net serializer which then blows up because it sees it's already serializing the object that was passed to it!

    打开ILSpy的DLL(是的,我知道它是开源的! - 但我想'来电'的功能)和 SerializeConvertable 调用栈向上移动到 JsonSerializerInternalWriter.SerializeValue 中,code,可检测是否应该使用一个转换器,临近开始时发现:

    Opening ILSpy on the DLL (yes I know it's open source - but I want the 'callers' functionality!) and moving up the call stack from SerializeConvertable to JsonSerializerInternalWriter.SerializeValue, the code that detects whether a converter should be used can be found right near the start:

    if (((jsonConverter = ((member != null) ? member.Converter : null)) != null 
       || (jsonConverter = ((containerProperty != null) ? containerProperty.ItemConverter 
                                                        : null)) != null 
       || (jsonConverter = ((containerContract != null) ? containerContract.ItemConverter 
                                                        : null)) != null 
       || (jsonConverter = valueContract.Converter) != null 
       || (jsonConverter = 
           this.Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null 
       || (jsonConverter = valueContract.InternalConverter) != null) 
       && jsonConverter.CanWrite)
    {
        this.SerializeConvertable(writer, jsonConverter, value, valueContract, 
                                  containerContract, containerProperty);
        return;
    }
    

    值得庆幸的是,在如果语句非常最后一个条件提供了解决我的问题:我所要做的就是下面的添加到任何基地转换器从复制的code在问题链接SO或在派生之一:

    Thankfully that very last condition in the if statement provides the solution to my issue: all I had to do was to add the following to either the base converter copied from the code in the linked SO in the question, or in the derived one:

    public override bool CanWrite
    {
        get
        {
            return false;
        }
    }
    

    现在,这一切工作正常。

    And now it all works fine.

    这样的结果,但问题在于,如果你打算有一个对象上一些自定义的JSON序列化,你用一个转换器注入它的 您打算退回到在某些或所有情况的标准序列化机制;那么你不能因为你欺骗框架以为你要存储一个循环引用。

    The upshot of this, however, is that if you intend to have some custom JSON serialization on an object and you are injecting it with a converter and you intend to fallback to the standard serialization mechanism under some or all situations; then you can't because you will fool the framework into thinking you're trying to store a circular reference.

    我也尝试操纵 ReferenceLoopHandling 成员,但如果我告诉了忽略然后将它们没有什么是系列化,如果我告诉它来拯救他们,勿庸置疑,我得到一个堆栈溢出。

    I did try manipulating the ReferenceLoopHandling member, but if I told it to Ignore them then nothing was serialized and if I told it to save them, unsurprisingly, I got a stack overflow.

    这是可能的,这是Json.Net错误 - 好吧这是这么多,它在脱落的宇宙边缘的危险的边缘的情况下 - 但如果你发现自己在这种情况下,那么你那种卡住!

    It's possible that this is a bug in Json.Net - alright it's so much of an edge-case that it's in danger of falling off the edge of the universe - but if you do find yourself in this situation then you're kind of stuck!

    这篇关于从定制JsonConverter在Json.Net JsonSerializer自参考环路(网页API)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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