[So and So Class] cannot be serialized because it does not have a parameterless constructor.Another point to keep in mind is that all public properties which needs to be serialized must have get and set methods implemented, else the following errors, when the property is read only or write only, will be thrown by the compiler at runtime.
InvalidOperationException with the following message will be thrown during serialization by the compiler if the property is declared read only (no set method defined) only.The same Car class illustrated in the previous article can be serialized into XML with the help of the below code.
“Unable to generate a temporary class (result=1).error CS0200: Property or indexer 'Cars.Car.Color' cannot be assigned to -- it is read only”
InvalidOperationException with a NullReferenceException as the inner exception will be thrown during serialization by the compiler if the property is write only (no get method defined) only.
InvalidOperationException message - "There was an error reflecting type 'Cars.Car'."
NullReferenceException message - "Object reference not set to an instance of an object."
using (System.IO.FileStream xmlFS = new System.IO.FileStream("car.xml", System.IO.FileMode.Create))
{
Cars.Car car = new Cars.Car { Model = "BMW 7 Series", Color = "Red", NoOfDoors = 4 };
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(car.GetType());
xmlSer.Serialize(xmlFS, car);
}
One thing to note here is that unlike Binary serialization only public properties and fields will be serialized. Private member variables will not be serialized. The serialized xml of the Car class is pasted below.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Color>Red</Color>
<Model>BMW 7 Series</Model>
<NoOfDoors>4</NoOfDoors>
<Price>0</Price>
</Car>
One more thing to note with XML serialization is that the class which needs to be serialized need not have a Serializable attribute applied to it like the one we used in binary serialization. To control XML serialization one needs to use attributes which control xml serialization. Some attributes which I think may be of use are listed below.
namespace Cars
{
public class Car
{
private string cubicCentimeter;
[System.Xml.Serialization.XmlIgnore]
public string Color
{ get; set; }
public string Model
{ get; set; }
public int NoOfDoors
{ get; set; }
public int Price
{ get; set; }
}
}
Serialized XML output after applying the XmlIgnore attribute.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Model>BMW 7 Series</Model>
<NoOfDoors>4</NoOfDoors>
<Price>0</Price>
</Car>
From the above xml one can see that the xml is missing the Color node as the XmlIgnore attribute is applied on it.
public class Car
{
private string cubicCentimeter;
[System.Xml.Serialization.XmlIgnore]
public string Color
{ get; set; }
[System.Xml.Serialization.XmlAttribute (AttributeName="CarModel")]
public string Model
{ get; set; }
public int NoOfDoors
{ get; set; }
public int Price
{ get; set; }
}
Serialized Xml output.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CarModel="BMW 7 Series">
<NoOfDoors>4</NoOfDoors>
<Price>0</Price>
</Car>
From the above xml you can see with the XmlAttribute added the Model property of the Car class has been converted as an Xml Attribute (highlighted in maroon) with the attribute name as “CarModel”. The attribute name is not same as that of the property name the reason being we have specified a different name by making use of AttributeName property of the XmlAttribute attribute.
IsNullable may not be 'true' for value type System.BlahBlah. Please consider using Nullable<System.BlahBlah> instead.Form property of XmlElement will tell serializer to whether qualify the XML element with a namespace or not. The accepted values are System.Xml.Schema.XmlSchem
//Form property wrongly used along with Namespace property
[System.Xml.Serialization.XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Namespace = "http://sandblogaspnet.com")]
public string Model
{ get; set; }
Error thrown as part of the above mistake.
“The Form property may not be 'Unqualified' when an explicit Namespace property is present.”
Order property in XmlElement will allow you to tell the serializer the order in which the XML element have to be serialized. If Order is used with any one property/field it has to be used with all the properties/fields. If not used with all the properties/field the compiler will throw a “System.InvalidOperationEx
Inconsistent sequencing: if used on one of the class's members, the 'Order' property is required on all particle-like members, please explicitly set 'Order' using XmlElement, XmlAnyElement or XmlArray custom attribute on class member ‘XYZ’.With Type you can specifies the type of the object. Sample code showing most of the properties of the XmlElement attribute are shown below.
namespace Cars
{
public class Car
{
private string cubicCentimeter;
[System.Xml.Serialization.XmlElement(Order = 2, IsNullable=true)]
public string Color
{ get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "ModelName", Order=1, IsNullable=true, DataType = "string")]
public string Model
{ get; set; }
[System.Xml.Serialization.XmlElement(Order = 3, Namespace = "http://sandblogaspnet.com", Form = System.Xml.Schema.XmlSchemaForm.Qualified)]
public int NoOfDoors
{ get; set; }
[System.Xml.Serialization.XmlElement(Order = 4)]
public int Price
{ get; set; }
}
}
//Car Class Initialization code.
Cars.Car car = new Cars.Car { Model = "BMW 7 Series", NoOfDoors = 4 };
Above Car class’ Serialized xml output.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ModelName>BMW 7 Series</ModelName>
<Color xsi:nil="true" />
<NoOfDoors xmlns="http://sandblogaspnet.com">4</NoOfDoors>
<Price>0</Price>
</Car>
One can see the serialized XML output of the Car class. An empty Color node with the xsi:nill attribute set to true because of the IsNullable attribute being set to true. Also notice the property Model being serialized as “ModelName” node because we have provided “ModelName” as the element name in the ElementName property of XmlElement attribute. Also you can notice an attribute called “xmlns” in ‘NoOfDoors” node added because of the Namespace property being used along with XmlElement attribute.
namespace Cars
{
[System.Xml.Serialization.XmlRoot(ElementName="Car",
DataType="Cars.Car", IsNullable=true,
Namespace="http://Cars.Car")]
public class Car
{
private string cubicCentimeter;
[System.Xml.Serialization.XmlElement(Order =
2, IsNullable=true)]
public string Color
{ get; set; }
[System.Xml.Serialization.XmlElement(ElementName
= "ModelName", Order=1, IsNullable=true, DataType =
"string")]
public string Model
{ get; set; }
[System.Xml.Serialization.XmlElement(Order =
3, Namespace = "http://sandblogaspnet.com", Form =
System.Xml.Schema.XmlSchemaForm.Qualified)]
public int NoOfDoors
{ get; set; }
[System.Xml.Serialization.XmlElement(Order =
4)]
public int Price
{ get; set; }
}
}
Serialized XML output for the above class.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://Cars.Car">
<ModelName>BMW 7 Series</ModelName>
<Color xsi:nil="true" />
<NoOfDoors xmlns="http://sandblogaspnet.com">4</NoOfDoors>
<Price>0</Price>
</Car>
XmlArray
public class CarCollection
{
[System.Xml.Serialization.XmlArrayItem(ElementName = "Car", Type = typeof(Car)), System.Xml.Serialization.XmlArrayItem(ElementName = "Ferrari", Type = typeof(Ferrari))]
public System.Collections.ArrayList Cars
{ get; set; }
}
If the XmlArrayItem is not used then the following error will be thrown by the compiler while serializing the collection.
System.InvalidOperationExcOne thing to note here is that if you are storing multiple types in a collection you have to specify all the types using the XmlArrayItem attribute. Even each derived classes have to be specified, just by specifying the parent class will not help. If you specify only the parent class then you can store only the parent class, trying to store the derived classes will throw the above error. So each an every derived class which you are planning to add in the collection needs to be specified. If any user type is missed then you will get the above error. Also if you are using the collection object to store .NET primitive types then there is no need to make use of the XmlArrayItem attribute. If you are making use of XmlArrayItem attribute to describe the primitive types in the collection then only the primitive types mentioned using the XmlArrayItem can be stored. Attempting to store primitive types other than the ones specified in the XmlArrayItem will throw the following error.eption - “There was an error generating the XML document.”
Inner Exception: “System.InvalidoperationException” - “The type Cars.Ferrari was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.”
System.InvalidOperationExcThe above error was thrown because I haven’t mentioned Double as one of the XmlArrayItem. Code is pasted below.eption - "There was an error generating the XML document."
Inner Exception: System.InvalidOperationException - "The type System.Double may not be used in this context."
[System.Xml.Serialization.XmlArrayItem(Type = typeof(string)), System.Xml.Serialization.XmlArrayItem(Type = typeof(int))]
public System.Collections.ArrayList PrimitiveTypes
{ get; set; }
So when the “PrimitiveTypes” property having a double value was serialized the above exception was thrown. So if your planning to store primitive types in a collection then its better not to decorate the property using the XmlArrayItem attribute. If you do then make sure you specify all the possible data types.
[System.Xml.Serialization.XmlInclude(typeof(Car)),
System.Xml.Serialization.XmlInclude(typeof(Ferrari)),
System.Xml.Serialization.XmlInclude(typeof(FerrariF500))]
public class CarCollection
{
public System.Collections.ArrayList Cars
{ get; set; }
}
If all the derived classes are not specified in the XmlInclude attribute then the same errors will be thrown as in XmlArrayItem.
public enum CarType
{
[System.Xml.Serialization.XmlEnum(Name="CompactCar")]
SmallCar,
[System.Xml.Serialization.XmlEnum(Name = "CompactSedan")]
CS,
Sedan,
SportsCar,
Suv
}
The Car class with the CarType enum added as a property and the serialized content of the car class is pasted below.
namespace Cars
{
[System.Xml.Serialization.XmlRoot(ElementName="Car", IsNullable=true )]
public class Car
{
System.Xml.Serialization.XmlElement(Order = 2, IsNullable=true)]
public string Color
{ get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "ModelName", Order=1, IsNullable=true)]
public string Model
{ get; set; }
[System.Xml.Serialization.XmlElement(Order = 3)]
public int NoOfDoors
{ get; set; }
[System.Xml.Serialization.XmlElement(Order = 4)]
public int Price
{
{ get; set; }
}
[System.Xml.Serialization.XmlAttribute(AttributeName="CarType")]
public CarType Type
{ get; set; }
}
}
// The class with the initial values
Cars.Car car = new Cars.Car { Model = "i20", NoOfDoors = 4, Color="Red", Type=Cars.CarType.SmallCar };
//Serialized XML for the above declared class.
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CarType="CompactCar">
<ModelName>i20</ModelName>
<Color>Red</Color>
<NoOfDoors>4</NoOfDoors>
<Price>0</Price>
</Car>
From the above class definition one can see the CarType enum is added as a property of the Car class. In the serialized XML one can see the CarType enum is serialized as an XML attribute because of the XmlAttribute applied on it in the Car class. Also note that the value of the CarType XML attribute is “CompactCar” instead “SmallCar”, this is because of the XmlEnum attribute applied in enum.
using (System.IO.FileStream xmlFS = new System.IO.FileStream("car.xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
System.Xml.Serialization.XmlSerializer xmlSerr = new System.Xml.Serialization.XmlSerializer(typeof(Cars.Car));
Cars.Car car = (Cars.Car)xmlSerr.Deserialize(xmlFS);
}
The below screenshot shows the properties deserialized and all the properties assigned.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (1)
Commented: