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:
<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>
My data:
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"]) }; } }
My model classes:
[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 + ")"; } }
and
[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>(); } }
Finally, the ApiController:
public class WeedAPIController : ApiController { // // GET: /WeedAPI/ public IEnumerable<Weed> GetAllWeeds() { return WeedData.GetWeeds(); } }
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With