2015-04-08 3 views
0

Сериализация простых (1: 1) родительских/дочерних циклических ссылок работает, как указано в сообщении mythz here. Тем не менее, я получаю исключение StackOverflowException при попытке сериализации родителя со списком детей, у которых есть ссылка обратно на родителя.ServiceStack.Text StackOverflowException с родительскими/дочерними круговыми ссылками

Я конденсировал это до голых костей tests и test classes на моем общем реплике Gib на GitHub.

Тесты:

/// <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

No. Циклические ссылки не работают. Даже в первом примере (Simple_ServiceStack) для сериализации я получаю:

{ "Текст": "Foo", "Детский": { "Номер": 2, "Родитель": { "Текст":» Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "ребенок": { "Номер": 2, "родитель": { "Текст": "Foo" , "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo",» Ребенок ": {" Номер ": 2," родитель ": {" Текст ":" Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Ребенок" : { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Number ": 2," родитель ": {" Текст ":" Foo», "ребенок": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": {» Текст ":" Foo», "Детский": { "Номер": 2, "Родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "Родитель": { "Текст" : "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст":» Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "ребенок": { "Номер": 2, "родитель": { "Текст": "Foo" , "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo",» Ребенок ": {" Номер ": 2," родитель ": {" Текст ":" Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Ребенок" : { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Number ": 2," родитель ": {" Текст ":" Foo», "ребенок": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель ": {" Текст ":" Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "текст": "Foo" , "Детский": { "Номер": 2, "Родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "Родитель": { "Текст": "Foo",» Ребенок ": {" Номер ": 2," родитель ": {" Текст ":" Foo», "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Ребенок" : { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Number ": 2," родитель ": {" Текст ":" Foo», "ребенок": { "Номер": 2, "родитель": { "Текст": "Foo", "Детский": { "Номер": 2, "родитель":}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}

это неправильно и сломана (см последнее "Parent":}). (Проверено с ServiceStack.Text 4.0.38)

Как написано в одном из комментариев:

Ваш пример DTO не круговыми ссылки - он использует различные объекты для каждого свойства линии

Как было предложено связанный с вами вопрос, используйте Json.NET с метаидами.

+0

Ха, я не понимал, что текст Json выглядит так. Я просто собирался пройти тест. Я не могу просто пойти с Json.NET, поскольку он не работает в Azure для меня (развернутый ... он работает локально). Мне нужна конкретная информация о типе, в которой есть ошибка в версии, которую Azure Mobile Services заморозила в среде сервера AMS (я думаю, 6.0.4). – ibgib

+0

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

+0

@ibgib Тогда, к сожалению, я не могу помочь :-( – xanatos

Смежные вопросы