【问题标题】:ServiceStack.Text StackOverflowException with Parent/Children circular references带有父/子循环引用的 ServiceStack.Text StackOverflowException
【发布时间】:2015-04-08 22:42:34
【问题描述】:

简单 (1:1) 父/子循环引用的序列化工作,如神话回答 here 中所述。但是,当尝试使用将 ref 保留给父级的子级列表来序列化父级时,我得到了 StackOverflowException。

我在 GitHub 上的 commonGib 存储库中将其简化为基本的 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

【问题讨论】:

  • 您能否重写此问题以将链接中的相关信息带入您的问题?您为我们做的工作越多,使回答变得容易,您就会得到更好的答案。
  • 啊,对不起。我不想向问题中的整个代码发送垃圾邮件。我可以这样做。
  • 不,不要那样做 - 只需添加相关部分。
  • 相关部分。我已经在我的 GitHub 存储库中剔除了代码。

标签: c# serialization stack-overflow servicestack-text


【解决方案1】:

没有。循环引用不起作用。即使在我得到的序列化的第一个示例(Simple_ServiceStack)中:

{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent" :{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{ "Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text ":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text": "Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo ","子":{"数字":2,"父":{"文本":"Foo","子":{"数字":2,"父":{"文本":"Foo", "子":{"数字":2,"父":{"文本":"Foo","子":{"数字":2,"父":{"文本":"Foo","子":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child": {"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{" Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number" :2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2 "父":{"文本": "Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo ","子":{"数字":2,"父":{"文本":"Foo","子":{"数字":2,"父":{"文本":"Foo", "子":{"数字":2,"父":{"文本":"Foo","子":{"数字":2,"父":{"文本":"Foo","子":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child": {"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{" Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number" :2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2 ,"父":{"文本":"Foo","子":{"数字":2,"父":{"文本":"Foo","子":{"数字":2," Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent" :{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{ "Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text ":"Foo","Chil d":{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child" :{"Number":2,"Parent":{"Text":"Foo","Child":{"Number":2,"Parent":{"Text":"Foo","Child":{ "数字":2,"父":}}}}}}}}}}}}}}}}}}}}}}}}}}}))}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}})}}}}}}}}}}))}}}}}}}}} }}}}}}}}}}}}

这是错误的坏了(见最后"Parent":})。 (用ServiceStack.Text 4.0.38测试)

如其中一个 cmets 所写:

您的示例 dto 没有使用循环引用 - 它为每个链接属性使用不同的对象

根据您链接的问题的建议,使用带有元 ID 的 Json.NET。

【讨论】:

  • 哈,我没有意识到 Json 文本看起来像那样。我只是去考试通过。我不能只使用 Json.NET,因为它在 Azure 中对我不起作用(已部署......它在本地工作)。我需要具体的类型信息,在 Azure 移动服务已冻结在 AMS 服务器环境中的版本(我认为是 6.0.4)中存在错误。
  • @ibgib 然后很遗憾我无能为力:-(
  • 我已将我的 Azure 移动服务后端迁移到新的 Azure Web/移动应用服务,它确实具有没有 Json.NET 6.0.4 限制的环境。序列化现在正在部署! (AFAICT :X) 任何其他遇到 Azure 移动服务版本问题的人都应该检查一下 Azure 的新服务和改进服务,看看它是否适合你。感谢您的帮助!
  • @ibgib 没问题,很高兴您解决了问题。
猜你喜欢
  • 2023-03-21
  • 2015-08-12
  • 1970-01-01
  • 2011-11-02
  • 1970-01-01
  • 2011-05-09
  • 2010-10-21
  • 1970-01-01
  • 2021-06-10
相关资源
最近更新 更多