在没有的情况下检测到自引用循环

时间:2017-07-21 15:05:31

标签: c# asp.net-core json.net

我有一个由TransformationPlanModel组成的数据模型,而IEnumerable<TransformationModel>又包含TransformationPlanModelTransformationModel是根数据传输对象。 TransformationPlanModel是其他转换模型的抽象基类。

public class TransformationPlanModel { // snip public IEnumerable<TransformationModel> Transformations { get; set; } } 的剪切代码:

TransformationModel

public abstract class TransformationModel { //snip public string Key { get; set; } } 的剪切代码:

RemoveRowsTransformationModel

具体的转型模型之一是public class RemoveRowsTransformationModel : TransformationModel { public const string KeyConst = "removeRows"; public int TopRowsCount { get; set; } public int BottomRowsCount { get; set; } public RemoveRowsTransformationModel() { Key = KeyConst; } //snip }

JsonConverter

我编写了一个自定义TransformationModel来转换JsonWrite继承树。 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { JObject.FromObject(value, serializer).WriteTo(writer); } 方法的实现是:

Startup.ConfigureServices

自定义转换器在ASP.NET Core API应用程序中使用,并添加到services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.Converters.Add(new TransformationConverter()); }); 方法中的服务中,如下所示:

TransformationPlanModel

Newtonsoft.Json.JsonSerializationException作为来自API端点的响应返回并被序列化时,会抛出JObject.FromObject,其中包含以下消息:“使用类型'(...)检测到自引用循环.RemoveRowsTransformationModel “”。是什么导致这个例外?我没有看到自引用循环的位置。我不知道它是否重要,但我使用的是.NET Core 2.0 Preview 1。

有趣的是,当WriteJson方法中使用不带序列化参数的public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { JObject.FromObject(value).WriteTo(writer); } 重载时,它可以正常工作:

{{1}}

然而,这会重置序列化设置,例如camel case属性命名。我也尝试忽略Json.Net设置中的循环引用,但是当时没有转换序列化。

1 个答案:

答案 0 :(得分:4)

在这种情况下,错误所指的“自引用循环”是您的转换器调用自身。串行器具有指示它使用转换器的设置。您的转换器调用JObject.FromObject(),传入序列化程序。 JObject.FromObject使用序列化程序尝试从模型中创建JObject。然后,串行器会再次调用转换器,依此类推。 Json.Net检测到这个递归循环并抛出异常。

一种可能的解决方案是使用新的序列化程序实例,复制原始序列化程序中除转换器之外的所有设置:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    JsonSerializer ser2 = new JsonSerializer();
    foreach (PropertyInfo prop in typeof(JsonSerializer).GetProperties()
            .Where(p => p.Name != nameof(JsonSerializer.Converters)))
    {
        prop.SetValue(ser2, prop.GetValue(serializer));
    }
    JObject.FromObject(value, ser2).WriteTo(writer);
}

但是,由于您的WriteJson方法似乎没有做任何其他事情,只是加载对象并立即将其写出而没有任何更改,更好的解决方案就是覆盖CanWrite以返回false 。然后根本不会调用WriteJson,而是使用默认序列化,这似乎就是你想要在这里发生的事情。

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