Lang verhaal kort: hoe krijg ik de XmlSerializer zover dat hij een graaf van objecten serialiseert waarin circulaire verwijzingen voorkomen?
Ik ben op dit moment bezig met een .NET 1.1 project waarbij gebruik wordt gemaakt van een webservice om data tussen client en server uit te wisselen. Binnen de client en server heeft deze data de vorm van business-objecten (zoals Bedrijf, Medewerker, etc.) die referenties hebben naar elkaar. Zo zal een Bedrijf een collectie van Medewerkers hebben, maar elke Medewerker heeft ook een referentie naar het Bedrijf waar hij werkt.
Nu is dit geen probleem zolang deze objecten zich in memory bevinden, maar (je voelt 'm waarschijnlijk al aankomen) wanneer zo'n graaf van objecten geserialiseerd moet worden naar XML om door de webservice heen te kunnen sturen gaat het mis. De XmlSerializer ondersteunt namelijk niet het serialiseren van een graaf van objecten met cykels. D.w.z: als je Bedrijf B wilt serializen, en B heeft een referentie naar Medewerker M dan gaat het goed, maar wanneer M op zijn beurt terugverwijst naar B dan krijg je een circulaire verwijzing en dan weigert de XmlSerializer dienst met de melding "A circular reference was detected while serializing an object of type Bedrijf.".
Omdat er conceptueel gezien niets mis is met circulaire verwijzingen, en dit imo een tekortkoming is van de XmlSerializer, zou ik 'm toch graag zo ver willen krijgen dat hij een cyclic object graph kan (de)serialiseren.
Nu heb ik een aantal alternatieven overwogen, maar allemaal voelen ze niet lekker:
Ik ben op dit moment bezig met een .NET 1.1 project waarbij gebruik wordt gemaakt van een webservice om data tussen client en server uit te wisselen. Binnen de client en server heeft deze data de vorm van business-objecten (zoals Bedrijf, Medewerker, etc.) die referenties hebben naar elkaar. Zo zal een Bedrijf een collectie van Medewerkers hebben, maar elke Medewerker heeft ook een referentie naar het Bedrijf waar hij werkt.
Nu is dit geen probleem zolang deze objecten zich in memory bevinden, maar (je voelt 'm waarschijnlijk al aankomen) wanneer zo'n graaf van objecten geserialiseerd moet worden naar XML om door de webservice heen te kunnen sturen gaat het mis. De XmlSerializer ondersteunt namelijk niet het serialiseren van een graaf van objecten met cykels. D.w.z: als je Bedrijf B wilt serializen, en B heeft een referentie naar Medewerker M dan gaat het goed, maar wanneer M op zijn beurt terugverwijst naar B dan krijg je een circulaire verwijzing en dan weigert de XmlSerializer dienst met de melding "A circular reference was detected while serializing an object of type Bedrijf.".
Omdat er conceptueel gezien niets mis is met circulaire verwijzingen, en dit imo een tekortkoming is van de XmlSerializer, zou ik 'm toch graag zo ver willen krijgen dat hij een cyclic object graph kan (de)serialiseren.
Nu heb ik een aantal alternatieven overwogen, maar allemaal voelen ze niet lekker:
- De graaf van objecten preprocessen door dubbele objecten te vervangen door stubs (= een plaatsvervangend object met alleen het ID-veld van het originele object) alvorens deze aan de XmlSerializer te geven. Echter, een stub moet precies van hetzelfde type zijn als het originele object (het kan niet eens van een afgeleide klasse zijn), dus dat komt neer op elk business object een public property te geven met of het al dan niet een stub voorstelt, en de rest van zijn velden op null zetten. Niet erg elegant.
- De velden van de businessobjecten decoreren met attributen die omschrijven welke relatie de inverse voorstelt van de relatie die met dit attribuut is gedecoreerd. De object graph kan dan voor het serializen worden gepreprocessed door, uitgaande van het root-object dat verstuurd wordt, alleen de verwijzingen naar child objecten te behouden, en alle parent-verwijzingen op null te zetten. Tijdens het deserialisen kan dan de omgekeerde weg bewandeld worden.
Echter, dit werkt alleen bij directe parent-child verwijzingen. Zo gauw er meer objecten in de cykel verwerkt zijn (A -> B -> C -> A) wordt het een puinhoop. - Een eigen XmlSerializer schrijven die voor objecten die al eens geserialized zijn alleen een referentie (bijv. een ID veld) wegschrijft. Verreweg de meest flexibele oplossing, maar hoogstwaarschijnlijk veel code en testen. Nadeel is wel dat dit reflection-gebaseerd zal moeten zijn, terwijl de XmlSerializer gebruik maakt van on-the-fly gegenereerde en gecompileerde classes om dit te realiseren. Waarschijnlijk dus een performance penalty.