XMLSerializer with complex object graphs - Suggestion perhaps
From: Richard Corfield (Corfield_at_discussions.microsoft.com)
Date: 11/26/04
- Next message: Juan Manuel Alegrķa B.: "How to view an icon on the taskmanager for a Windows Service"
- Previous message: Param R.: "Re: middle tier recommendations"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 26 Nov 2004 07:55:03 -0800
I'm using XMLSerializer to serialize complex object graphs - fortunately
Directionally Acyclic in this case. I'm trying to avoid serialising things
more than once. The problem is, that in my graphs there's more than one route
to the leaf. Searching around and reading the documentation, I've not seen a
way to solve this provided out of the box.
The way I've solved it is to mark the child collection as [XmlIgnore] so it
is not serialised, and instead mark each node with a Guid and provide an
alternate property which lists the child Guids. That is what is serialised.
Fortunately it is easy for me to get a list of all existant children at the
root level, so the root serialises this list first. The fun comes on
deserialisation. My child elements contain a link back to the root (cyclic
dependency, ouch), also marked [XmlIgnore] and passed down in the parent's
addChild() method. The setter for this ChildIDs property just stores the
array of IDs that is given. When the real Child collection is asked for, the
node asks the root to resolve all the IDs using its master list of all
existant children. This lazy resolution ensures that I don't try to resolve
the children before all the information is available.
The XML for a directionaly acyclic graph could look something like this:
<Root>
<KnownNodes>
<Node id="1">
<Name>Fred</Name>
<Children><NodeLink refID="2"/><NodeLink refID="3"/></Children>
</Node>
<Node id="2">
<Name>Jane</Name>
<Children><NodeLink refID="3"/></Children>
</Node>
<Node id="3">
<Name>Jack</Name>
<Children></Children>
</Node>
</KnownNodes>
<TopLevelNodes>
<NodeLink refID="1"/>
</TopLevelNodes>
</Root>
I've shortened the Guids to make the above easier to write.
What would be nice would be for the Framework to do this for me. My first
thought would be that we could mark an attribute, or set of attributes, as
being the "Primary Key" for the class. An identifier if you like. The Guid
IDs are excellent candidates.
[XmlIdentifier]
public Guid Id { get { return m_id;} set { m_id = value; } }
Then we could have the framework not serialise something again if its
already seen it, but instead store a reference to it. The problem with this
is that it would make the generated XML Schema unpredictable as we'd not know
for a Child in my example above whether we're going to get the child, or a
reference. We'd have to use a Choice everywhere in the schema. Perhaps it
could work.
An alternative would be to explicitely serialise all reachable instances at
the given root level. A marker that says "Serialse all reachable Nodes from
here". If it could be implemented as a Class level attribute (in the C#
sense, not the XML sense) then perhaps:
[XmlAllReachable(PropertyName="TopLevelNodes",
ElementName="KnownNodes")]
which would combine with the [XmlIdentifier] above to achieve the required
effect.
The advantage of this is that it would become easily possible to serialise
complex graphs where there is a chance of their being more than one route
from the Root to a given class. We'd still have to [XmlIgnore] parent links.
The real advantage is that the quite complex code to manage deserialisation
using the current system (I'm on Dot Net 2.0) would go away as the framework
would do it for me.
- Next message: Juan Manuel Alegrķa B.: "How to view an icon on the taskmanager for a Windows Service"
- Previous message: Param R.: "Re: middle tier recommendations"
- Messages sorted by: [ date ] [ thread ]