Circular references preventing serialization of object graph

Circular references preventing serialization of object graph

I've got a simple data model involving Weeds and Weed Families.  
WeedFamily <-1---*-> Weed (WeedFamily and Weed have a one-to-many relationship)
I'm attempting to complete my first ApiController so that I can easily retrieve my data as JSON for an AngularJS application.  When I access the /WeedAPI/ URL in my application, I get the following error.  I'm pretty sure the problem is that I have circular references between Weed and WeedFamily.
How should I change my data model so that the JSON serialization will work while maintaining the bi-directional quality of the Weed-WeedFamily relationship?
(ie. I want to still be able to build expressions like the following:
 WeedData.GetFamilies()["mustard"].Weeds.Count

and 
WeedData.GetWeeds()[3].Family.Weeds

) 
The error:

    An error has occurred.
    
        The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
    
    System.InvalidOperationException
    
    
        An error has occurred.
        
            Object graph for type 'WeedCards.Models.WeedFamily' contains cycles and cannot be serialized if reference tracking is disabled.
        
        
            System.Runtime.Serialization.SerializationException
        
        
            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
        
    


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

    public static List GetWeeds(){
        var Families = GetFamilies();
        return new List
        {
             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"])

        };
    }
}

My model classes:
[Serializable]
public class Weed
{
    public string CommonName;
    public string LatinName;
    public List 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 + ")";
    }
}

and
[Serializable]
public class WeedFamily
{
    public string CommonName;
    public string LatinName;
    public List Weeds;

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

Finally, the ApiController:
public class WeedAPIController : ApiController
{
    //
    // GET: /WeedAPI/

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

}

Solutions/Answers:

Answer 1:

Add [DataContract(IsReference = true)] to the objects that have circular references.

[Serializable]
[DataContract(IsReference = true)]
public class WeedFamily

[Serializable]
[DataContract(IsReference = true)]
public class Weed

See http://msdn.microsoft.com/en-us/library/vstudio/hh241056(v=vs.100).aspx

Our Awesome Tools

References