By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,652 Members | 1,487 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,652 IT Pros & Developers. It's quick & easy.

Xml Serializing subclass problem

P: n/a
Hi guys. I've come across a problem when I tried to serialize a class into
xml, only to discover that the parent class's XML Serialization properties
weren't included in the output xml.

Actually, the class I'm serializing is two steps down in the inheritance
ladder. It's got a parent class which also has a parent class :( All those
classes in the hierarchy are Xml Serializable, and I'd think that it should
be obvious that all attributes/properties of the parents should be
serialized for any given subclass, no ?
Here's the two classes, subclass first, parent classes afterwards:
[XmlRootAttribute(Namespace="", ElementName="Group", IsNullable=false)]
public class Group : CBusLogicalObject
{
private Unit[] m_units = null;
public Group() : base()
{
}
public Group(string strAddress, CBusNode parent)
: base(strAddress, parent) {
}
public Group(string strAddress, string strName, CBusNode parent)
: base(strAddress, strName, parent) {
}
[XmlArrayItem(ElementName="units", Type=typeof(Unit))]
[XmlArray(ElementName="units")]
public Unit[] Units {
get { return m_units;}
set {
// TODO: Add some validation logic here ...
m_units = value;
}
}
}

... and the parent ...

[XmlRootAttribute(Namespace="", ElementName="LObject", IsNullable=false)]
public abstract class CBusLogicalObject : CBusNode
{
public CBusLogicalObject() : base()
{
}
public CBusLogicalObject(string strAddress, CBusNode parent)
: base(strAddress, parent){
m_address = parent.Address+"/"+strAddress;
}
public CBusLogicalObject(string strAddress, string strName, CBusNode parent)
: base(strAddress, strName, parent){
m_address = parent.Address+"/"+strAddress;
}
}

... and the paren't parent ( don't blame me ... :D )

[XmlRootAttribute(Namespace="", ElementName="CBusNode", IsNullable=false)]
public abstract class CBusNode
{
protected string m_address = null;
protected string m_name = null;
private CBusNode _parent = null;
public CBusNode()
{
}
public CBusNode(string address, CBusNode parent) {
this._parent = parent;
this.m_address = address;
}
public CBusNode(string address, string name, CBusNode parent) {
this._parent = parent;
this.m_address = m_address;
this.m_name = name;
}
[XmlAttributeAttribute(AttributeName="Address")]
public string Address {
get { return m_address; }
}
[XmlAttributeAttribute(AttributeName="Name")]
public string Name {
get {return m_name; }
}

Thanks a lot for any help,
Cheers,
Angel
O:]
Nov 12 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Start with easier example such as below. Note private fields will not be
serialized. Public fields and public properties with both get and set will
be. Null fields will also not be serialized by default.

DerivedClass dc = new DerivedClass();
string xml = dc.ToXmlString();
Console.WriteLine(xml);

public class BaseClass
{
public string BaseString = "Hello"; // public.
private string notSerialized; // not xmlserialized as private.
private string base2String = "Happy Holidays"; // property is public.

public BaseClass()
{
notSerialized = "not";
Console.WriteLine(notSerialized); // remove compiler warning.
}

public string Base2String
{
get { return base2String; }
set { base2String = value; } // Both get/set required by xmlseralizer.
}
}

public class DerivedClass : BaseClass
{
private static XmlSerializer ser = new XmlSerializer(typeof(DerivedClass));

public string DerivedString = "There";

public DerivedClass() : base()
{
}

public string ToXmlString()
{
byte[] bytes = ToBytes(false);
return Encoding.UTF8.GetString(bytes);
}

public static DerivedClass FromXmlString(string xmlString)
{
if ( xmlString == null )
throw new ArgumentNullException("xmlString");

DerivedClass xr = null;
using(StringReader sr = new StringReader(xmlString))
{
xr = (DerivedClass)ser.Deserialize(sr);
return xr;
}
}

/// <summary>
/// Serialize class to utf-8 encoded byte array. Serialize defaults to
/// using UTF8 so we can avoid an additional XmlWriter stream.
/// </summary>
/// <param name="prefixLen"></param>
/// <returns></returns>
public byte[] ToBytes(bool prefixLen)
{
using(MemoryStream ms = new MemoryStream())
{
if ( prefixLen )
ms.Position = 4;

ser.Serialize(ms, this);

if ( prefixLen )
{
if ( ms.Length > uint.MaxValue )
throw new ArgumentException("Serialized class bigger then
uint.MaxValue");
uint len = (uint)ms.Length;
byte[] lenBytes = BitConverter.GetBytes(len);
ms.Position = 0;
ms.Write(lenBytes, 0, lenBytes.Length);
}
return ms.ToArray();
}
}
}

-- Output --
<?xml version="1.0"?>
<DerivedClass xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<BaseString>Hello</BaseString>
<Base2String>Happy Holidays</Base2String>
<DerivedString>There</DerivedString>
</DerivedClass>

--
William Stacey, MVP
http://mvp.support.microsoft.com

"Angelos Karantzalis" <ak**********@yahoo.com> wrote in message
news:O2**************@TK2MSFTNGP11.phx.gbl...
Hi guys. I've come across a problem when I tried to serialize a class into
xml, only to discover that the parent class's XML Serialization properties
weren't included in the output xml.

Actually, the class I'm serializing is two steps down in the inheritance
ladder. It's got a parent class which also has a parent class :( All those
classes in the hierarchy are Xml Serializable, and I'd think that it should be obvious that all attributes/properties of the parents should be
serialized for any given subclass, no ?
Here's the two classes, subclass first, parent classes afterwards:
[XmlRootAttribute(Namespace="", ElementName="Group", IsNullable=false)]
public class Group : CBusLogicalObject
{
private Unit[] m_units = null;
public Group() : base()
{
}
public Group(string strAddress, CBusNode parent)
: base(strAddress, parent) {
}
public Group(string strAddress, string strName, CBusNode parent)
: base(strAddress, strName, parent) {
}
[XmlArrayItem(ElementName="units", Type=typeof(Unit))]
[XmlArray(ElementName="units")]
public Unit[] Units {
get { return m_units;}
set {
// TODO: Add some validation logic here ...
m_units = value;
}
}
}

.. and the parent ...

[XmlRootAttribute(Namespace="", ElementName="LObject", IsNullable=false)]
public abstract class CBusLogicalObject : CBusNode
{
public CBusLogicalObject() : base()
{
}
public CBusLogicalObject(string strAddress, CBusNode parent)
: base(strAddress, parent){
m_address = parent.Address+"/"+strAddress;
}
public CBusLogicalObject(string strAddress, string strName, CBusNode parent) : base(strAddress, strName, parent){
m_address = parent.Address+"/"+strAddress;
}
}

.. and the paren't parent ( don't blame me ... :D )

[XmlRootAttribute(Namespace="", ElementName="CBusNode", IsNullable=false)]
public abstract class CBusNode
{
protected string m_address = null;
protected string m_name = null;
private CBusNode _parent = null;
public CBusNode()
{
}
public CBusNode(string address, CBusNode parent) {
this._parent = parent;
this.m_address = address;
}
public CBusNode(string address, string name, CBusNode parent) {
this._parent = parent;
this.m_address = m_address;
this.m_name = name;
}
[XmlAttributeAttribute(AttributeName="Address")]
public string Address {
get { return m_address; }
}
[XmlAttributeAttribute(AttributeName="Name")]
public string Name {
get {return m_name; }
}

Thanks a lot for any help,
Cheers,
Angel
O:]


Nov 12 '05 #2

P: n/a
Thanks for the reply Will. I think the original problem was caused because
the "parent's parent" class CBusNode had the Address & Name properties
read-only (no set in the properties). I saw that after I'd send the post,
corrected it, but now I get some very weird exception upon running the test
application, about missing a DLL library with cryptic name - plus it throws
the same exception with a different cryptic dll name every time, as if the
dll name were random!

.... gosh, just when I was saying how nice Xml Serialization is in .NET as
opposed to some Java APIs. Guess again ! :?

Cheers,
Angel
O:]
"William Stacey [MVP]" <st***********@mvps.org> wrote in message
news:ue**************@TK2MSFTNGP12.phx.gbl...
Start with easier example such as below. Note private fields will not be
serialized. Public fields and public properties with both get and set will be. Null fields will also not be serialized by default.

DerivedClass dc = new DerivedClass();
string xml = dc.ToXmlString();
Console.WriteLine(xml);

public class BaseClass
{
public string BaseString = "Hello"; // public.
private string notSerialized; // not xmlserialized as private.
private string base2String = "Happy Holidays"; // property is public.

public BaseClass()
{
notSerialized = "not";
Console.WriteLine(notSerialized); // remove compiler warning.
}

public string Base2String
{
get { return base2String; }
set { base2String = value; } // Both get/set required by xmlseralizer.
}
}

public class DerivedClass : BaseClass
{
private static XmlSerializer ser = new XmlSerializer(typeof(DerivedClass));
public string DerivedString = "There";

public DerivedClass() : base()
{
}

public string ToXmlString()
{
byte[] bytes = ToBytes(false);
return Encoding.UTF8.GetString(bytes);
}

public static DerivedClass FromXmlString(string xmlString)
{
if ( xmlString == null )
throw new ArgumentNullException("xmlString");

DerivedClass xr = null;
using(StringReader sr = new StringReader(xmlString))
{
xr = (DerivedClass)ser.Deserialize(sr);
return xr;
}
}

/// <summary>
/// Serialize class to utf-8 encoded byte array. Serialize defaults to
/// using UTF8 so we can avoid an additional XmlWriter stream.
/// </summary>
/// <param name="prefixLen"></param>
/// <returns></returns>
public byte[] ToBytes(bool prefixLen)
{
using(MemoryStream ms = new MemoryStream())
{
if ( prefixLen )
ms.Position = 4;

ser.Serialize(ms, this);

if ( prefixLen )
{
if ( ms.Length > uint.MaxValue )
throw new ArgumentException("Serialized class bigger then
uint.MaxValue");
uint len = (uint)ms.Length;
byte[] lenBytes = BitConverter.GetBytes(len);
ms.Position = 0;
ms.Write(lenBytes, 0, lenBytes.Length);
}
return ms.ToArray();
}
}
}

-- Output --
<?xml version="1.0"?>
<DerivedClass xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<BaseString>Hello</BaseString>
<Base2String>Happy Holidays</Base2String>
<DerivedString>There</DerivedString>
</DerivedClass>

--
William Stacey, MVP
http://mvp.support.microsoft.com

"Angelos Karantzalis" <ak**********@yahoo.com> wrote in message
news:O2**************@TK2MSFTNGP11.phx.gbl...
Hi guys. I've come across a problem when I tried to serialize a class into xml, only to discover that the parent class's XML Serialization properties weren't included in the output xml.

Actually, the class I'm serializing is two steps down in the inheritance
ladder. It's got a parent class which also has a parent class :( All those classes in the hierarchy are Xml Serializable, and I'd think that it

should
be obvious that all attributes/properties of the parents should be
serialized for any given subclass, no ?
Here's the two classes, subclass first, parent classes afterwards:
[XmlRootAttribute(Namespace="", ElementName="Group", IsNullable=false)]
public class Group : CBusLogicalObject
{
private Unit[] m_units = null;
public Group() : base()
{
}
public Group(string strAddress, CBusNode parent)
: base(strAddress, parent) {
}
public Group(string strAddress, string strName, CBusNode parent)
: base(strAddress, strName, parent) {
}
[XmlArrayItem(ElementName="units", Type=typeof(Unit))]
[XmlArray(ElementName="units")]
public Unit[] Units {
get { return m_units;}
set {
// TODO: Add some validation logic here ...
m_units = value;
}
}
}

.. and the parent ...

[XmlRootAttribute(Namespace="", ElementName="LObject", IsNullable=false)] public abstract class CBusLogicalObject : CBusNode
{
public CBusLogicalObject() : base()
{
}
public CBusLogicalObject(string strAddress, CBusNode parent)
: base(strAddress, parent){
m_address = parent.Address+"/"+strAddress;
}
public CBusLogicalObject(string strAddress, string strName, CBusNode

parent)
: base(strAddress, strName, parent){
m_address = parent.Address+"/"+strAddress;
}
}

.. and the paren't parent ( don't blame me ... :D )

[XmlRootAttribute(Namespace="", ElementName="CBusNode", IsNullable=false)] public abstract class CBusNode
{
protected string m_address = null;
protected string m_name = null;
private CBusNode _parent = null;
public CBusNode()
{
}
public CBusNode(string address, CBusNode parent) {
this._parent = parent;
this.m_address = address;
}
public CBusNode(string address, string name, CBusNode parent) {
this._parent = parent;
this.m_address = m_address;
this.m_name = name;
}
[XmlAttributeAttribute(AttributeName="Address")]
public string Address {
get { return m_address; }
}
[XmlAttributeAttribute(AttributeName="Name")]
public string Name {
get {return m_name; }
}

Thanks a lot for any help,
Cheers,
Angel
O:]

Nov 12 '05 #3

P: n/a
> application, about missing a DLL library with cryptic name - plus it
throws
the same exception with a different cryptic dll name every time, as if the
dll name were random!


It is kinda random. A dynamic dll gets created by xmlserializer for your
class. At the moment, I forget why that was necessary or if that step could
be avoided. Would need to see the error message to be sure, but it must be
something to do with issue of serialization or deserialization.

--
William Stacey, MVP
http://mvp.support.microsoft.com
Nov 12 '05 #4

P: n/a
Well, after a whole lot of debugging & playing around & a little help from:
http://weblogs.asp.net/cschittko/articles/33045.aspx I solved the problems.

I just cast the instace being serialized inot the base class in the
XmlSerializer & included the derived classes with an [XmlInclude] attribute
in the parent class.

Thanks for the help William.

Cheers,
Angel
O:]
"William Stacey [MVP]" <st***********@mvps.org> wrote in message
news:Oz*************@TK2MSFTNGP09.phx.gbl...
application, about missing a DLL library with cryptic name - plus it throws
the same exception with a different cryptic dll name every time, as if the dll name were random!


It is kinda random. A dynamic dll gets created by xmlserializer for your
class. At the moment, I forget why that was necessary or if that step

could be avoided. Would need to see the error message to be sure, but it must be something to do with issue of serialization or deserialization.

--
William Stacey, MVP
http://mvp.support.microsoft.com

Nov 12 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.