2015-04-08 51 views
0

如神話回答here中所述,簡單(1:1)父/子循環引用的序列化工作正常。然而,當我試圖序列化父對象時,我得到了一個StackOverflowException,這個父對象擁有一個引用父對象的子對象列表。ServiceStack.Text帶父/子循環引用的StackOverflowException

我在GitHub上的commonGib repo上將其縮減爲裸骨teststest classes

測試:

/// <summary> 
/// Trivial business classes with a simple 1:1 circular relationship, i.e. Parent.Child, Child.Parent. 
/// </summary> 
[TestMethod] 
public void Simple_ServiceStack() 
{ 
    var parent = new SimpleParent() { Text = "Foo" }; 
    var child = new SimpleChild() { Number = 2 }; 

    parent.Child = child; 
    child.Parent = parent; 

    var parentJson = JsonSerializer.SerializeToString(parent); 

    var parentTest = JsonSerializer.DeserializeFromString<SimpleParent>(parentJson); 

    Assert.IsTrue(parentTest.TextEqualsFoo()); 
    Assert.IsTrue(parentTest.Child.NumberEqualsTwo()); 
} 

/// <summary> 
/// Test business classes more complex by having a parent with a list of children, as opposed 
/// to a 1:1 relationship, i.e. Parent.Children instead of Parent.Child. 
/// </summary> 
[TestMethod] 
public void Complex_ServiceStack() 
{ 
    var parent = new ComplexParent() { Text = "Foo" }; 
    var child = new ComplexChild() { Number = 2 }; 

    parent.Children = new List<ComplexChild>() { child }; 
    child.Parent = parent; 

    var parentJson = JsonSerializer.SerializeToString(parent); //Throws stack overflow 

    var parentTest = JsonSerializer.DeserializeFromString<ComplexParent>(parentJson); 

    Assert.IsTrue(parentTest.TextEqualsFoo()); 
    foreach (var childTest in parentTest.Children) 
    { 
     Assert.IsTrue(childTest.NumberEqualsTwo()); 
    } 
} 

/// <summary> 
/// Real-world business classes wrapped around a state class. 
/// </summary> 
[TestMethod] 
public void VeryComplex_ServiceStack() 
{ 
    var parentState = new VeryComplexParentState() { Text = "Foo" }; 
    var childState = new VeryComplexChildState() { Number = 2 }; 

    var parent = new VeryComplexParent() { State = parentState }; 
    var child = new VeryComplexChild() { State = childState }; 

    parent.Children = new List<VeryComplexChild>() { child }; 
    child.Parent = parent; 

    var parentJson = JsonSerializer.SerializeToString(parent); //Throws stack overflow 

    var parentTest = JsonSerializer.DeserializeFromString<ComplexParent>(parentJson); 

    Assert.IsTrue(parentTest.TextEqualsFoo()); 
    foreach (var childTest in parentTest.Children) 
    { 
     Assert.IsTrue(childTest.NumberEqualsTwo()); 
    } 
} 

測試類:

#region Simple Parent/Child 

public class SimpleParent 
{ 
    public string Text { get; set; } 
    public SimpleChild Child { get; set; } 

    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool TextEqualsFoo() 
    { 
     return Text == "Foo"; 
    } 
} 

public class SimpleChild 
{ 
    public int Number { get; set; } 
    public SimpleParent Parent { get; set; } 

    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool NumberEqualsTwo() 
    { 
     return Number == 2; 
    } 
} 

#endregion 

#region Complex Parent/Child 

public class ComplexParent 
{ 
    public string Text { get; set; } 
    public List<ComplexChild> Children { get; set; } 

    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool TextEqualsFoo() 
    { 
     return Text == "Foo"; 
    } 
} 

public class ComplexChild 
{ 
    public int Number { get; set; } 
    public ComplexParent Parent { get; set; } 

    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool NumberEqualsTwo() 
    { 
     return Number == 2; 
    } 
} 

#endregion 

#region Very Complex Parent/Child 

public abstract class BaseSerializationTestClass<TState>// : BaseSerializationTestClass 
{ 
    public TState State { get; set; } 
} 


public class VeryComplexParent : BaseSerializationTestClass<VeryComplexParentState> 
{ 
    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool TextEqualsFoo() 
    { 
     return State != null && State.Text == "Foo"; 
    } 

    public List<VeryComplexChild> Children { get; set; } 
} 

public class VeryComplexParentState 
{ 
    public string Text { get; set; } 

    public List<VeryComplexChildState> MyChildrenState { get; set; } 
} 

public class VeryComplexChild : BaseSerializationTestClass<VeryComplexChildState> 
{ 
    /// <summary> 
    /// This is like a validation rule on the state wrapper. 
    /// </summary> 
    public bool NumberEqualsTwo() 
    { 
     return State != null && State.Number == 2; 
    } 

    public VeryComplexParent Parent { get; set; } 
} 

public class VeryComplexChildState 
{ 
    public int Number { get; set; } 

    public VeryComplexParentState MyAState { get; set; } 
} 

#endregion 
+0

你能否重寫這個問題,將鏈接中的相關信息帶入你的問題?你做更多的工作讓我們回答容易得到更好的答案。 – Enigmativity

+0

啊,對不起。我不想在問題中發送垃圾郵件。我可以這樣做。 – ibgib

+0

不,不要那樣做 - 只需添加**相關**部分即可。 – Enigmativity

回答

1

號循環引用不工作。甚至在序列化你的第一個例子(Simple_ServiceStack)我得到:

{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」:」富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」 , 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」,」孩子 「:{」 編號 「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」 :{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{「號「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」: 2, 「父母」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{」文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文本」 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」:」富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」 , 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」,」孩子 「:{」 編號 「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」 :{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{「號「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」: 2, 「父母」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2,「父「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」: {「文」:「富」 , 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」,」孩子 「:{」 編號 「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」 :{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{「號「:2,」 父 「:{」 文 「:」 富」, 「孩子」:{ 「編號」:2, 「父」:{ 「文」: 「富」, 「孩子」:{ 「編號」: 2, 「父」:}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}

這是不對的破碎(見最後"Parent":})。 (帶ServiceStack.Text 4.0.38測試)

作爲寫在評論中的一個:

你的示例DTO沒有使用循環引用 - 它是使用對於每個鏈路屬性

不同的物體如所建議的通過你鏈接的問題,使用JSON.NET與meta ID。

+0

哈,我沒有意識到Json文本看起來像這樣。我只是在通過測試。我不能只使用Json.NET,因爲它不適用於Azure(部署...它在本地工作)。我需要具體的類型信息,Azure移動服務在AMS服務器環境中凍結的版本中存在一個錯誤(我認爲是6.0.4)。 – ibgib

+0

http://stackoverflow.com/questions/27080363/missingmethodexception-with-newtonsoft-json-when-using-typenameassemblyformat-wi – ibgib

+0

@ibgib然後可悲的是我不禁:-( – xanatos