2013-08-22 15 views
20

Ho un semplice modello di dati che coinvolge Weeds e Weed Families.Riferimenti circolari che impediscono la serializzazione del grafico dell'oggetto

WeedFamily <-1---*-> Weed (WeedFamily e Weed hanno una relazione uno-a-molti)

sto cercando di completare il mio primo ApiController in modo che possa facilmente recuperare i miei dati come JSON per un'applicazione AngularJS. Quando accedo all'URL /WeedAPI/ nella mia applicazione, ottengo il seguente errore. Sono abbastanza sicuro che il problema è che ho riferimenti circolari tra Weed e WeedFamily.

Come devo modificare il modello di dati in modo che la serializzazione JSON funzioni pur mantenendo la qualità bidirezionale della relazione Weed - WeedFamily?

(. Cioè voglio essere ancora in grado di costruire espressioni come la seguente:

WeedData.GetFamilies()["mustard"].Weeds.Count 

e

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

)

L'errore:

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

I miei dati:

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"]) 

     }; 
    } 
} 

mie classi del modello:

[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 + ")"; 
    } 
} 

e

[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>(); 
    } 
} 

Infine, l'ApiController:

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

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

} 
+1

Perché stai facendo override 'ToString()'? Probabilmente vuoi semplicemente usare l'attributo '[DebuggerDisplay]'. – ANeves

risposta

35

Aggiungi [DataContract(IsReference = true)] agli oggetti che hanno riferimenti circolari.

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

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

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

+0

Ho bisogno di un'importazione per usare quell'attributo? 'Non è stato possibile trovare il nome dello spazio dei nomi 'DataContractAttribute' –

+1

Sì, si trova nello spazio dei nomi' System.Runtime.Serialization' – Hack

+1

Risulta necessario aggiungere 'System.Runtime.Serialization.dll' come riferimento nel mio progetto VS : http://stackoverflow.com/questions/7401795/namespace-for-datacontract Dopo che ho fatto che la mia serializzazione funzionava correttamente! Grazie. –

Problemi correlati