2017-07-21 24 views
1

我有一個由TransformationPlanModel組成的數據模型,它又包含一個IEnumerable<TransformationModel>TransformationPlanModel是根數據傳輸對象。 TransformationModel是其他轉換模型的抽象基類。自檢迴路檢測到沒有的地方

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它轉換th e繼承樹。 JsonWrite方法的實現是:

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

自定義轉換器在ASP.NET核心API應用程序中使用和添加到服務於Startup.ConfigureServices方法,像這樣:

services.AddMvc().AddJsonOptions(options => 
{ 
    options.SerializerSettings.Converters.Add(new TransformationConverter()); 
}); 

TransformationPlanModel作爲API端點的響應返回並被序列化,則會引發一個Newtonsoft.Json.JsonSerializationException,其中包含消息:「檢測到類型爲'(...).ReadRowsTransformationModel'」的自回參考循環。什麼導致這種異常?我無法看到自引用循環的位置。我不知道它的問題,但我使用.NET核2.0預覽1.

有趣的是,當JObject.FromObject沒有串行參數的重載在WriteJson方法時,它工作正常:

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

但是,這會重置序列化設置,如駝峯屬性命名。我也嘗試忽略Json.Net設置中的循環引用,但是沒有任何轉換被序列化。

回答

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