循环引用阻止对象图的序列化

22

我有一个简单的数据模型,涉及到杂草和杂草家族。

WeedFamily <-1---*-> Weed(WeedFamily 和 Weed 之间是一对多关系)

我正在尝试完成我的第一个 ApiController,以便可以轻松地检索我的数据作为 JSON,供 AngularJS 应用程序使用。当我在应用程序中访问 /WeedAPI/ URL 时,会出现以下错误。我相信问题是我在WeedWeedFamily之间存在循环引用导致的。

我该如何更改我的数据模型,以便在保持Weed-WeedFamily双向质量的同时使 JSON 序列化工作?

(也就是说,我仍然希望能够构建以下表达式:

 WeedData.GetFamilies()["mustard"].Weeds.Count
WeedData.GetWeeds()[3].Family.Weeds

错误:

<Error>
    <Message>An error has occurred.</Message>
    <ExceptionMessage>
        The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
    </ExceptionMessage>
    <ExceptionType>System.InvalidOperationException</ExceptionType>
    <StackTrace/>
    <InnerException>
        <Message>An error has occurred.</Message>
        <ExceptionMessage>
            Object graph for type 'WeedCards.Models.WeedFamily' contains cycles and cannot be serialized if reference tracking is disabled.
        </ExceptionMessage>
        <ExceptionType>
            System.Runtime.Serialization.SerializationException
        </ExceptionType>
        <StackTrace>
            at System.Runtime.Serialization.XmlObjectSerializerWriteContext.OnHandleReference(XmlWriterDelegator xmlWriter, Object obj, Boolean canContainCyclicReference) at WriteWeedToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract ) at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDecl...etc
        </StackTrace>
    </InnerException>
</Error>

我的数据:

public class WeedData
{
    public static Dictionary<string,WeedFamily> GetFamilies(){
        return new Dictionary<string,WeedFamily>
        {
             {"mustard",new WeedFamily("Mustard","Brassicaceae")}
            ,{"pigweed",new WeedFamily("Pigweed","Amaranthus")}
            ,{"sunflower",new WeedFamily("Sunflower","Asteraceae")}
        };
    }

    public static List<Weed> GetWeeds(){
        var Families = GetFamilies();
        return new List<Weed>
        {
             new Weed("Hairy Bittercress","Cardamine hirsuta",Families["mustard"])
            ,new Weed("Little Bittercress","Cardamine oligosperma",Families["mustard"])
            ,new Weed("Shepherd's-Purse","Capsella bursa-pastoris",Families["mustard"])
            ,new Weed("Wild Mustard","Sinapis arvensis / Brassica kaber",Families["mustard"])
            ,new Weed("Wild Radish","Raphanus raphanistrum",Families["mustard"])
            ,new Weed("Radish","Raphanus sativus",Families["mustard"])
            ,new Weed("Redroot Pigweed","Amaranthus retroflexus",Families["pigweed"])
            ,new Weed("Prickly Lettuce","Lactuca serriola",Families["sunflower"])
            ,new Weed("Spiny Sowthistle","Sonchus asper",Families["sunflower"])
            ,new Weed("Annual Sowthistle","Sonchus oleraceus",Families["sunflower"])

        };
    }
}

我的模型类:

[Serializable]
public class Weed
{
    public string CommonName;
    public string LatinName;
    public List<WeedPhoto> Photos;
    public WeedFamily Family;

    public Weed(string commonName, string latinName)
    {
        CommonName = commonName;
        LatinName = latinName;
    }

    public Weed(string commonName, string latinName, WeedFamily family)
    {
        CommonName = commonName;
        LatinName = latinName;
        Family = family;
        Family.Weeds.Add(this);
    }

    override public string ToString()
    {
        return CommonName + " (" + LatinName + ")";
    }
}

[Serializable]
public class WeedFamily
{
    public string CommonName;
    public string LatinName;
    public List<Weed> Weeds;

    public WeedFamily(string commonName, string latinName)
    {
        CommonName = commonName;
        LatinName = latinName;
        Weeds = new List<Weed>();
    }
}

最后,ApiController:

public class WeedAPIController : ApiController
{
    //
    // GET: /WeedAPI/

    public IEnumerable<Weed> GetAllWeeds()
    {
        return WeedData.GetWeeds();
    }

}

1
你为什么重写 ToString() 方法?你可能只需要使用 [DebuggerDisplay] 特性。 - ANeves
1个回答

38

我需要导入才能使用那个属性吗?“找不到类型或命名空间名称'DataContractAttribute'” - Jonathan Wilson
1
是的,它在 System.Runtime.Serialization 命名空间中。 - Hack
1
结果发现我需要在我的VS项目中添加System.Runtime.Serialization.dll作为引用:https://dev59.com/Jms05IYBdhLWcg3wLO6Q 在我这样做之后,我的序列化工作正常了!谢谢。 - Jonathan Wilson
如果我使用JSON序列化器会怎样? - AMH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接