Regarding performance on objects serialized to Xml - thoughts and code presented

A

Anders Borum

Hello Jon, et all.

I am working on a framework with context bound objects (models). The objects
expose common functionality, such as the ability to get a serialized Xml
representation of an object (and its hierarchy if available).

In order to guarantee that wellformed Xml, I use an XmlTextWriter on top of
a StringWriter. I didn't even look at a custom serialization service, as
that would be like reinventing the wheel (atleast thats how I looked at it).

Ok, great so far - but when serializing larger amounts of objects (e.g. 256
or more), the performance is not what I had expected (please note that it is
not the object navigation that is slow, it's the serialization).

I know that programmers would typically cache the generated Xml, but
performance is very important to me and I don't want to cut any corners in a
framework.

For flexibility, I have been thinking about using an abstract pattern,
defining an abstract ObjectSerializerBase then providing a concrete
ElementObjectSerializer etc. for each object type provided by the API. This
would allow a programmer to provide his own concrete serializer to the
serialization, resulting in a quicker process and smaller Xml fragment

Some initial thoughts on the abstract code is presented in the end of this
posting.

Any suggestions to how I could improve the performance in the following code
(aside from the abstract)? I am looking for constructive critique, so don't
hold your breath :)

C#
public string ToXml()
{
StringWriter sW = new StringWriter();
XmlTextWriter XmlW = Xml.XmlTextWriter(sW);

ToXml(XmlW);

XmlW.Close();
return sW.ToString();
}

internal protected void ToXml(XmlTextWriter XmlW)
{
XmlW.WriteStartElement("Element");
{
XmlW.WriteAttributeString("ElementID", elementID);
etc.

XmlW.WriteElementString("ElementName", elementName);
etc.

XmlW.WriteStartElement("ElementXml");
{
XmlW.WriteRaw(ElementXml);
}
XmlW.WriteEndElement();
}

// Serialize Areas (using existing XmlTextWriter)
Areas.ToXml(XmlW);

// Serialize PlaceHolders (using existing XmlTextWriter)
PlaceHolders.ToXml(XmlW);

XmlW.WriteEndElement();
}

public string ToXml()
{
StringWriter sW = new StringWriter();
XmlTextWriter XmlW = Xml.XmlTextWriter(sW);

ToXml(XmlW);

XmlW.Close();
return sW.ToString();
}

internal protected void ToXml(XmlTextWriter XmlW)
{
XmlW.WriteStartElement("Element");
{
XmlW.WriteAttributeString("ElementID", elementID);
etc.

XmlW.WriteElementString("ElementName", elementName);
etc.

XmlW.WriteStartElement("ElementXml");
{
XmlW.WriteRaw(ElementXml);
}
XmlW.WriteEndElement();
}

// Serialize Areas (using existing XmlTextWriter)
Areas.ToXml(XmlW);

// Serialize PlaceHolders (using existing XmlTextWriter)
PlaceHolders.ToXml(XmlW);

XmlW.WriteEndElement();
}

...

Here's how an abstract version could look like:

C#
// Base class
public abstract ObjectSerializerBase
{
public abstract void ToXml(XmlTextWriter XmlW, CmsObjectNode o);
}

// Concrete serializer class for the type Element
public class ElementObjectSerializer : ObjectSerializerBase
{
public override void ToXml(XmlTextWriter XmlW, CmsObjectNode o)
{
Element e = (Element) o;

XmlW.WriteStartElement("Element");
{
.. include only the necessary attributes / elements
}
XmlW.WriteEndElement();
}
}

// This would be an overloaded method on all objects
public string ToXml(ObjectSerializerBase o)
{
StringWriter sW = new StringWriter();
XmlTextWriter XmlW = Xml.XmlTextWriter(sW);

o.ToXml(XmlW, this);

XmlW.Close();
return sW.ToString();

}

Any ideas? :)
 
A

Anders Borum

This code snippet doesn't contain the redundant functions in the original
e-mail. I'm sorry if that confused the code listing a little. This should be
used as reference.

C#
public string ToXml()
{
StringWriter sW = new StringWriter();
XmlTextWriter XmlW = Xml.XmlTextWriter(sW);

ToXml(XmlW);

XmlW.Close();
return sW.ToString();
}

internal protected void ToXml(XmlTextWriter XmlW)
{
XmlW.WriteStartElement("Element");
{
XmlW.WriteAttributeString("ElementID", elementID);
etc.

XmlW.WriteElementString("ElementName", elementName);
etc.

XmlW.WriteStartElement("ElementXml");
{
XmlW.WriteRaw(ElementXml);
}
XmlW.WriteEndElement();
}

// Serialize Areas (using existing XmlTextWriter)
Areas.ToXml(XmlW);

// Serialize PlaceHolders (using existing XmlTextWriter)
PlaceHolders.ToXml(XmlW);

XmlW.WriteEndElement();
}

...

Here's how an abstract version could look like:

C#
// Base class
public abstract ObjectSerializerBase
{
public abstract void ToXml(XmlTextWriter XmlW, CmsObjectNode o);
}

// Concrete serializer class for the type Element
public class ElementObjectSerializer : ObjectSerializerBase
{
public override void ToXml(XmlTextWriter XmlW, CmsObjectNode o)
{
Element e = (Element) o;

XmlW.WriteStartElement("Element");
{
.. include only the necessary attributes / elements
}
XmlW.WriteEndElement();
}
}

// This would be an overloaded method on all objects
public string ToXml(ObjectSerializerBase o)
{
StringWriter sW = new StringWriter();
XmlTextWriter XmlW = Xml.XmlTextWriter(sW);

o.ToXml(XmlW, this);

XmlW.Close();
return sW.ToString();

}

Any ideas? :)
 
N

Nicholas Paldino [.NET/C# MVP]

Anders,

But you are using a custom serialization service, namely, yours. Why
not use XmlSerializer or the SoapFormatter? Each of these will persist your
object into XML (in different formats, and using different methodologies),
but it will work.

Other than that, I would ditch the XmlTextWriter and use a StringBuilder
instance and add the XML to that. That's probably going to give you the
best performance.

Hope this helps.
 
A

Anders Borum

Hello!

What a quick reply already!
But you are using a custom serialization service, namely, yours. Why
not use XmlSerializer or the SoapFormatter? Each of these will persist your
object into XML (in different formats, and using different methodologies),
but it will work.

I have intentionally provide my own "schema" in the serialization, as I
consider this serialization different - and it's intented use is very
different from the situations where you'd usually resort to the
XmlSerializer or SoapFormater (e.g. when you need core data from the API and
transform it to a navigation structure using Xsl).

I actually tried the XmlSerializer approach and it was a little slower than
the XmlTextWriter approach. Given the abstract model I presented, I think
that would solve my problem with the speed. With a hierarchical navigation
structure, the programmer rarely needs anything but some identifiers and a
few properties from the objects.
Other than that, I would ditch the XmlTextWriter and use a StringBuilder
instance and add the XML to that. That's probably going to give you the
best performance.

I realize that this is another option, but I have to guarentee valid Xml and
would accept the performance penaulty if that ment that I didn't have to
come up with my own encoding of illegal chars. I would rather provide some
alternatives as to caching etc.

Thanks for sharing your thoughts!
 
Top