Hi,
I am trying to use Xml Serialization in order to serialize and deserialize an object for a webservice and for a database operations.
Here is an example of the class structure:

public abstract class Forniture {
	private float m_Price;

	public abstract int color{get; set;}
	
	[XmlElement(DataType="float"))]
	public float price{
		get{return m_Price;}
		set{m_Price=value;}
	}
...
...
...
}

public class Chair : Forniture {
	private float m_Price;

	[XmlElement(DataType="int"))]
	public override int color{
		get {return 1;}
		set {m_Color=value;}
	}
...
...
...
}

public class Table : Forniture {
	private float m_Price;

	[XmlElement(DataType="int"))]
	public override int color{
		get {return 2;}
		set {m_Color=value;}
	}
...
...
...
}

public class Closet : Forniture {
	private float m_Price;

	[XmlElement(DataType="int"))]
	public override int color{
		get {return 3;}
		set {m_Color=value;}
	}
...
...
...
}

public class Room {
	private List<Forniture> m_Fornitures;

	[XmlArray(ElementName="forni"),
	 XmlArrayItem(Type=typeof(Fornitures), ElementName="item")]
	public Forniture[] Fornitures {
		get {return m_Fornitures.ToArray();}
		set {m_Fornitures=new List<Forniture>(value);}
	}

	public Room() {
		m_Fornitures=new List<Forniture>();
	}

	public void AddForniture(Forniture f) {
		m_Fornitures.add(f);
	}
}


public class Bathroom:Room {
	private string m_member1;
	private string m_member2;

	[XmlElement(DataType="string"))]
	public string Member1 {
		get {return m_member1;}
		set {m_member1=value;}
	}

	[XmlElement(DataType="string"))]
	public string Member2 {
		get {return m_member1;}
		set {m_member2=value;}
	}

	public Bathroom():base() {
		m_member1="214";
		m_member2="sasdd";
		AddForniture(new Closet());
		AddForniture(new Table());
	}
}

When serialize and deserialize object Bathroom, the problems are:
1. When asp.net deserialize the object (javascript calls webservice with the serialized object), it throws an exception because class Forniture is abstract. When I change Forniture class to not being abstract, asp.net convert all the fornitures to Forniture instance instead of the relevand instance (Closet, Table or Chair). How can I serialize/deserialize the inheritance properly so I can solve this problem?
2. Do I use XmlSerialization right?

Thanks!

XML Serialization does not figure out the type automagically. When you instantiate the XML Serializer for example:

XmlSerializer ser = new XmlSerializer(typeof(AcctInfo));

The .NET framework will use reflection to call the constructor for AcctInfo (or in your case furniture) that doesn't have any parameters, so new AcctInfo(). So if you're telling it to deserialize with your abstract class then it is trying to construct an abstract class which cannot be done. You either need to distinguish the data being serialized by some method (putting a 1 byte header in the data, different url to post to, etc) or take control of serialization by hand.

Thanks for your reply.

I am recieving the deserialized object via the asp.net mechanizem from javascript client code.
I am not handling the deserialization myself.
Therefore I get Bathroom object with array of Forniture that contains forniture and not chair/table (the data doesn't containing members of chair etc..).

How can I retrieve the right data with the right members?

That could be a good thing, you could get a toilet in the middle of living room and a couch in your bathroom :)

On a more serious note... can you paste some code up here of what is happening? I'm imaging you're getting a string with the serialized data in it, and then you're trying to deserialize from that? You could take a look at the data and see what type it is perhaps... I need to see exactly what you're doing here though.

I will paste my code, but it is long and not so obvios as the example about fornitures I wrote. I will also delete irrelevant code in order to make it simple.
I have a class "Task":

public class Task3
    {
        private long m_TaskId;
        private string m_CustomerCompanyNumber;
	private GroupType m_GroupType; //GroupType is Enum
        private DateTime m_StartDate;
	
	//CustomFieldData soposed to be abstract and is has 4 sons class - this field is the problem.
        private List<CustomFieldData> m_CustomFieldsData;

	//TaskContainer is a class with 4 string members - I will not add this class for simplicity.
        private TaskContainer m_TaskContainer = null;

        [XmlElement(DataType = "long")]
        public long TaskId
        {
            get { return m_TaskId; }
            set { m_TaskId = value; }
        }


        [XmlElement(DataType = "string")]
        public string GroupTypeName
        {
            get { return Enum.GetName(typeof(GroupType), m_GroupType); }
            set
            {
                if (Enum.IsDefined(typeof(GroupType), value))
                {
                    m_GroupType = (GroupType)Enum.Parse(typeof(GroupType), value);
                }
            }
        }

        public GroupType GroupType
        {
            get { return m_GroupType; }
        }


        [XmlElement(DataType = "string")]
        public string CustomerCompanyNumber
        {
            get { return m_CustomerCompanyNumber; }
            set { m_CustomerCompanyNumber = value; }
        }

        [XmlElement(Type = typeof(DateTime))]
        public DateTime StartDate
        {
            get { return m_StartDate; }
            set { m_StartDate = value; }
        }

        [XmlArray(ElementName="CustomFields")]
        public CustomFieldData[] CustomFieldsData
        {
            get { return m_CustomFieldsData.ToArray(); }
            set
            {
                m_CustomFieldsData = new List<CustomFieldData>(value);
            }
        }

        [XmlElement(Type = typeof(TaskContainer))]
        public TaskContainer TaskContainer
        {
            get { return m_TaskContainer; }
            set { m_TaskContainer = value; }
        }

        //C'tors+other methods
    }

Class CustomFieldDatasoposed to be abstract but I cannot make it abstract - it throws an exception when deserialize happened:

public class CustomFieldData
    {
        private CustomFieldType m_CustomFieldType;

        [XmlElement(DataType = "string")]
        public string Type
        {
            get { return Enum.GetName(typeof(CustomFieldType), m_CustomFieldType); }
            set
            {
                if (Enum.IsDefined(typeof(CustomFieldType), value))
                {
                    m_CustomFieldType = (CustomFieldType)Enum.Parse(typeof(CustomFieldType), value);
                }
            }
        }
        //public abstract long CustomFieldId { get; set; }
        //public abstract string CustomFieldName { get; set; }
        //public abstract string Value { get; set; }

        public CustomFieldData() { }

        public CustomFieldData(CustomFieldType type)
        {
            m_CustomFieldType = type;
        }
    }

I have 4 classes that inherits CustomFieldData but I will show only 2 of them because it is enough info:

class FieldData : CustomFieldData
    {
        private long m_FieldId;
        private string m_FieldName;
        private string m_Value;

        [XmlElement(DataType = "long")]
        public long CustomFieldId //Soposed to be override property
        {
            get { return m_FieldId; }
            set { m_FieldId = value; }
        }

        [XmlElement(DataType = "string")]
        public string CustomFieldName //Soposed to be property method
        {
            get { return m_FieldName; }
            set { m_FieldName = value; }
        }

        [XmlElement(DataType = "string")]
        public string Value //Soposed to be override property
        {
            get { return m_Value; }
            set { m_Value = value; }
        }

        public FieldData() { }

        public FieldData(long id, string name, string value)
            : base(CustomFieldType.CustomField)
        {
            m_FieldId = id;
            m_FieldName = name;
            m_Value = value;
        }
    }

    class ListData : CustomFieldData
    {
        private long m_ListInGroupId;
        private string m_ListName;
        private string m_Value;
        private long m_ValueId;

        [XmlElement(DataType = "long")]
        public long CustomFieldId //Soposed to be override property
        {
            get { return m_ListInGroupId; }
            set { m_ListInGroupId = value; }
        }

        [XmlElement(DataType = "string")]
        public string CustomFieldName //Soposed to be override property
        {
            get { return m_ListName; }
            set { m_ListName = value; }
        }

        [XmlElement(DataType = "string")]
        public string Value //Soposed to be override property
        {
            get { return m_Value; }
            set { m_Value = value; }
        }

        public long ValueId
        {
            get { return m_ValueId; }
            set { m_ValueId = value; }
        }

        public ListData() { }

        public ListData(long id, string name, long valueId)
            : base(CustomFieldType.CustomList)
        {
            m_ListInGroupId = id;
            m_ListName = name;
            m_ValueId = valueId;
            m_Value = CustomGroupsDBHandler.GetListItem(m_ListInGroupId, valueId);
        }

        public ListData(long id, string name, long valueId, string value)
            : base(CustomFieldType.CustomList)
        {
            m_ListInGroupId = id;
            m_ListName = name;
            m_ValueId = valueId;
            m_Value = value;
        }
    }

I have also class Movement that inherit class Task. Movement and Task are deserialized ok except of the CustomFieldsData array member that all of its items are CustomFieldData and therefore doesn't contains the CustomListData members (ValueId, Value, CustomFieldName, CustomFieldId for example).

What I am doing is the following:
1. From client code (javascript) I call a webservice that returns Movement. Here the data serialized great and I have all the data I need with the right properties.
2. The user make some operations and clicks on the "approve" button. The updated data sent back to the server (the user didn't touch and didn't change the CustomFieldData array data).
3. Data sent back to the server and deserialized automatically using the asp.net webservice mechanizem (I think).
4. The data didn't serialized weel and instead of getting the correct data in the CustomFieldData array, I get an array with CustomFieldData items. For example:
CustomFieldData contains: {FieldData, FieldData, ListData}
after data sent back to the server, CustomFieldData contains {CustomFieldData,CustomFieldData,CustomFieldData} and therefore I am loosing information (I don't have the ValueId member and casting throws an exception). The deserialization creates CustomFieldData objects and not what I really need. Where in fact, at the beginning, I needed the class CustomFieldData to be abstract!

How Can I get the proper data?
Thank you very much!

The only thing I know to say is that you need to know the final type of the XML before you serialize it, it cannot be the base class. I'm not familiar with what you're doing here, you might be better off posting this to the ASP.NET forum since it has more to do with the postback instead of c#.

Sorry :(

Hi again,
I know the exect types on runtime. But I am not the one who serialize the data. asp.NET serialize it and so I cannot control it.
Do you know asp.net forum with normal activity that can help me?

Thanks!

http://www.daniweb.com/forums/forum18.html

Maybe if you could paste the code or link to a site that explained how the asp.net serializes the object client-side and transmits it then I could help you. I haven't seen any examples of it, but i don't do too much web development either. Post the code you're using pertinent to the serialization or shoot me to a URL and i'll give it a shot.

Hi,
If I would know how the asp.net serializes the object client-side and transmits it, I would manage to solve my problem..

Thanks for you tryings.
If you have any idea, please let me know.

This article has been dead for over six months. Start a new discussion instead.