Serializing Collections of Objects

Standard

System.Object represents a complete tree of objects. Given this, if we pass in an object that has been marked as [Serializable] and contains other [Serializable] objects, the entire set of objects is persisted in a single method call. As luck would have it, most of the types you find in the System.Collections and System.Collections.Generic namespaces have already been marked as [Serializable]. Therefore, if we wish to persist a set of objects, simply add the desired set to the container (such as an ArrayList or a List<T>) and serialize the object to your stream of choice.

First Example Code:

Now assume that we want to update the MyLuxuryCar class with a two-argument constructor, so we can set a few pieces of state data:

[Serializable, XmlRoot(Namespace = "https://mushfiqrazib.wordpress.com")]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
[XmlAttribute(AttributeName = "CanFly")]
public bool CanJump;
public bool hasWaterProofSystem;
}

With this, we can now persist any number of MyLuxuryCar objects:

private static void Main(string[] args)
{
string PersistingXMLFileName = "MyLuxuryFerrariCollection.xml";
List myCarList = new List();
myCarList.Add(new MyLuxuryCar(true, true));
myCarList.Add(new MyLuxuryCar(true, false));
myCarList.Add(new MyLuxuryCar(false, true));
myCarList.Add(new MyLuxuryCar(false, false));
// Serialize myCar object.
SaveObjectAsXmlFormat(myCarList, PersistingXMLFileName);
// Deserialize myCar object from the xml file
DeserializeObjectFromXMLFormat(myCarList, PersistingXMLFileName);
Console.Read();
}
static void SaveObjectAsXmlFormat(object objGraph, string fileName)
{// Save object to a file in XML format.
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamWriter writer = new StreamWriter(fileName))
{
Console.WriteLine("<<>>");
xmlFormatter.Serialize(writer, objGraph);
Console.WriteLine("Object list saved to xml");
}
}

After the serialization, the collection objects state information into the xml file will be shown below:

<?xml version=”1.0″ encoding=”utf-8″?>

<ArrayOfMyLuxuryCar xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;

  <MyLuxuryCar CanFly=”true”>

    <hasAutomaticWeaponSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt;

false </hasAutomaticWeaponSystem>

    <hasWaterProofSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt; true </hasWaterProofSystem>

  </MyLuxuryCar>

  <MyLuxuryCar CanFly=”true”>

    <hasAutomaticWeaponSystem xmlns=”https://mushfiqrazib.wordpress.com”>false</hasAutomaticWeaponSystem&gt;

    <hasWaterProofSystem xmlns=”https://mushfiqrazib.wordpress.com”>false</hasWaterProofSystem&gt;

  </MyLuxuryCar>

  <MyLuxuryCar CanFly=”false”>

    <hasAutomaticWeaponSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt; false </hasAutomaticWeaponSystem>

    <hasWaterProofSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt; true </hasWaterProofSystem>

  </MyLuxuryCar>

  <MyLuxuryCar CanFly=”false”>

    <hasAutomaticWeaponSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt; false </hasAutomaticWeaponSystem>

    <hasWaterProofSystem xmlns=”https://mushfiqrazib.wordpress.com”&gt; false </hasWaterProofSystem>

  </MyLuxuryCar>

</ArrayOfMyLuxuryCar>


In the ControlledXMLSerializationTest class, we also define DeserializeObjectFromXMLFormat method given below for deserialization of the collection objects which are now stored in the xml file. After calling the method from the main method, it shows the number of collections of MyLuxuryCar is 4.

static void DeserializeObjectFromXMLFormat(object objGraph, string filename)
{
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamReader reader = new StreamReader(filename))
{
Console.WriteLine("<<>>");
List myCarList = (List)xmlFormatter.Deserialize(reader);
Console.WriteLine("Object list generated from xml. TOtal cars : {0}",myCarList.Count);
}
}

Second Example Code:

Suppose we have a Department class and Employee class. We can list employees of a department and want to store the information in a xml file. In the below code snippet two classes are defined:

[Serializable]
public class Department
{
public string Name { get; set; }
public List Employees { get; set; }
public Department()
{
Employees = new List();
}
}
[Serializable]
public class Employee
{
public string Name { get; set; }
public Employee() { }
public Employee(string name)
{
Name = name;
}
}

And for serialization, in the main method, we use the following code :

string PersistingXMLFileForEmployee = "EmployeeCollection.xml";
Department dept = new Department();
dept.Name = "IT";
dept.Employees.Add(new Employee("Razib"));
dept.Employees.Add(new Employee("Rakib"));
dept.Employees.Add(new Employee("Mushfiq"));
SaveObjectAsXmlFormat(dept, PersistingXMLFileForEmployee);
Console.Read();

And the generated xml file is given below:

<?xml version=”1.0″ encoding=”utf-8″?>

<Department xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”  xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;

  <Name>IT</Name>

  <Employees>

    <Employee>

      <Name> Razib</Name>

    </Employee>

    <Employee>

      <Name>Rakib</Name>

    </Employee>

    <Employee>

      <Name>Mushfiq</Name>

    </Employee>

  </Employees>

</Department>

XmlArray
The first attribute we will consider is XmlArray. This can be applied to properties that are declared as arrays or collections. It modifies the outer XML element for the property. A common use for this attribute is modifying the name of the outer element. In the Department class below, the XmlArray attribute has been applied to the Employees list. This changes the name of the generated collection element.

[Serializable]
public class Department
{
public string Name { get; set; }
[XmlArray("Staff")]
public List Employees { get; set; }
public Department()
{
Employees = new List();
}
}

After serialization you can see that the Employees element has been renamed to “Staff”.

<?xml version=”1.0″ encoding=”utf-8″?>

<Department xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”  xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;

  <Name>IT</Name>

  <Staff>

    <Employee>

      <Name>Razib</Name>

    </Employee>

    <Employee>

      <Name>Rakib</Name>

    </Employee>

    <Employee>

      <Name>Mushfiq</Name>

    </Employee>

  </Staff>

</Department>

XmlArrayItem
The XmlArrayItem attribute is used to modify the inner elements that each represent an item from the collection. If we want to use a custom name for the elements instead of the data type, we can provide it in a similar manner as with XmlArray. In the following updated Department class the attribute specifies that the inner elements should be named, “StaffMember”. The XmlArray attribute is also present.

[Serializable]
public class Department
{
public string Name { get; set; }
[XmlArray("SoftwareEngineers")]
[XmlArrayItem("SoftwareDeveloper")]
public List Employees { get; set; }
public Department()
{
Employees = new List();
}
}

Resulting xml file will be:

<?xml version=”1.0″ encoding=”utf-8″?>

<Department xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”  xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;

  <Name>IT</Name>

  <SoftwareEngineers>

    <SoftwareDeveloper>

      <Name>Razib</Name>

    </SoftwareDeveloper>

    <SoftwareDeveloper>

      <Name>Rakib</Name>

    </SoftwareDeveloper>

    <SoftwareDeveloper>

      <Name>Mushfiq</Name>

    </SoftwareDeveloper>

  </SoftwareEngineers>

</Department>

The full code snippet is given below:

public class ControlledXMLSerializationTest
{
private static void Main(string[] args)
{
string PersistingXMLFileName = "MyLuxuryFerrariCollection.xml";
List myCarList = new List();
myCarList.Add(new MyLuxuryCar(true, true));
myCarList.Add(new MyLuxuryCar(true, false));
myCarList.Add(new MyLuxuryCar(false, true));
myCarList.Add(new MyLuxuryCar(false, false));
// Serialize myCar object.
SaveObjectAsXmlFormat(myCarList, PersistingXMLFileName);
// Deserialize myCar object from the xml file
DeserializeObjectFromXMLFormat(myCarList, PersistingXMLFileName);
string PersistingXMLFileForEmployee = "EmployeeCollection.xml";
Department dept = new Department();
dept.Name = "IT";
dept.Employees.Add(new Employee("Razib"));
dept.Employees.Add(new Employee("Rakib"));
dept.Employees.Add(new Employee("Mushfiq"));
SaveObjectAsXmlFormat(dept, PersistingXMLFileForEmployee);
Console.Read();
}
static void SaveObjectAsXmlFormat(object objGraph, string fileName)
{
// Save object to a file in XML format.
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamWriter writer = new StreamWriter(fileName))
{
Console.WriteLine("<<>>");
xmlFormatter.Serialize(writer, objGraph);
Console.WriteLine("Object list saved to xml");
}
}
static void DeserializeObjectFromXMLFormat(object objGraph, string filename)
{
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamReader reader = new StreamReader(filename))
{
Console.WriteLine("<<>>");
List myCarList = (List)xmlFormatter.Deserialize(reader);
Console.WriteLine("Object list generated from xml. TOtal cars : {0}",myCarList.Count);
}
}
}
[Serializable]
public class Car
{
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo, hasAutomaticWeaponSystem);
}
}
[Serializable, XmlRoot(Namespace = "https://mushfiqrazib.wordpress.com")]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
[XmlAttribute(AttributeName = "CanFly")]
public bool CanJump;
public bool hasWaterProofSystem;
}
[Serializable]
public class Department
{
public string Name { get; set; }
[XmlArray("SoftwareEngineers")]
[XmlArrayItem("SoftwareDeveloper")]
public List Employees { get; set; }
public Department()
{
Employees = new List();
}
}
[Serializable]
public class Employee
{
public string Name { get; set; }
public Employee() { }
public Employee(string name)
{
Name = name;
}
}
}

Controlling XML Serialization

Standard

Controlling the Generated XML Data

By default, XmlSerializer serializes all public fields/properties as XML elements, rather than as XML attributes. But we can control how the XmlSerializer generates the resulting XML document by using any number of additional .NET attributes from the System.Xml.Serialization namespace. Some (but not all) of the .NET attributes that influence how XML data is encoded to a stream.

  • [XmlAttribute]  – Can use this .NET attribute on a public field or property in a class to tell XmlSerializer to serialize the data as an XML attribute (rather than as a subelement).
  • [XmlElement] – The field or property will be serialized as an XML element named as choose.
  • [XmlEnum] – This attribute provides the element name of an enumeration member.
  • [XmlRoot] – This attribute controls how the root element will be constructed (namespace and element name).
  • [XmlText] – The property or field will be serialized as XML text (i.e. the content between the start tag and the end tag of the root element).
  • [XmlType] – This attribute provides the name and namespace of the XML type.

This simple example illustrates how the field data of MyLuxuryCar is currently persisted as XML:

<?xml version=”1.0″ encoding=”utf-8″?>
<MyLuxuryCar xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;
<radio>
<hasMicrophonePoint>true</hasMicrophonePoint>
<hasSubwoofers>true</hasSubwoofers>
<playStations>
<double>88</double>
<double>89.6</double>
<double>100.2</double>
<double>99.8</double>
</playStations>
<stationID>FM-88.9_Radio Foorti</stationID>
</radio>
<hasAutomaticWeaponSystem>true</hasAutomaticWeaponSystem>
<Model>Ferrari</Model>
<Color>Black</Color>
<CanJump>true</CanJump>
<hasWaterProofSystem>true</hasWaterProofSystem>
</MyLuxuryCar>

Sometimes we will want to change the name of the XML attribute so that the property name is not used. We can do so using the AttributeName parameter, which accepts a string containing the new name. As with other parts of a serialized XML document, such as the root element or individual child elements, we can specify the namespace for each attribute. To do so, set the value of the Namespace parameter. When a namespace is applied to an attribute, a namespace prefix is required. The serializer automatically generates prefixes for each unique namespace used.

Now,  to specify a custom XML namespace that qualifies the MyLuxuryCar and encodes the CanJump as CanFly and hasWaterProofSystem values as XML attributes, we can do so by modifying the C# definition of MyLuxuryCar:

[Serializable, XmlRoot(Namespace = "https://mushfiqrazib.wordpress.com")]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
[XmlAttribute(AttributeName="CanFly")]
public bool CanJump;
[XmlAttribute(Namespace="http://www.mushfiqrazib.com")]
public bool hasWaterProofSystem;
}

And in the Car class, we want to decorate the public property hasAutomaticWeaponSystem with XmlIgnore attribute for not adding the information into the xml document. Here, we use Model property as an attribute whose name will be ModelName in the xml document. The modified Car class is given below:

[Serializable]
public class Car
{
public Radio radio = new Radio();
[XmlIgnore]
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
[XmlAttribute(AttributeName="ModelName")]
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo, hasAutomaticWeaponSystem);
}
}

So, after the serialization, the xml document will be look like the below one:

<?xml version=”1.0″ encoding=”utf-8″?>
<MyLuxuryCar xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
             xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;
             ModelName=”Ferrari”
             CanFly=”true”
             d1p1:hasWaterProofSystem=”true”
             xmlns:d1p1=”http://www.mushfiqrazib.com&#8221;
             xmlns=”https://mushfiqrazib.wordpress.com&#8221;>
  <radio>
    <hasMicrophonePoint>true</hasMicrophonePoint>
    <hasSubwoofers>true</hasSubwoofers>
    <playStations>
      <double>88</double>
      <double>89.6</double>
      <double>100.2</double>
      <double>99.8</double>
    </playStations>
    <stationID>FM-88.9_Radio Foorti</stationID>
  </radio>
  <Color>Black</Color>
</MyLuxuryCar>

The full code snippet is given below:

public class ControlledXMLSerializationTest
{
private static void Main(string[] args)
{
string PersistingXMLFileName = "MyControlledLuxuryFerrari.xml";
Car myCar = new MyLuxuryCar(true, true);
myCar.Color = "Black";
myCar.Model = "Ferrari";
myCar.hasAutomaticWeaponSystem = true;
myCar.AddMiles(2000);
myCar.AddCrashes(5);
myCar.radio.hasSubwoofers = true;
myCar.radio.playStations = new double[] { 88.0, 89.6, 100.2, 99.8 };
myCar.radio.hasMicrophonePoint = true;
// Serialize myCar object.
SaveObjectAsXmlFormat(myCar, PersistingXMLFileName);
// Deserialize myCar object from the xml file
DeserializeObjectFromXMLFormat(myCar, PersistingXMLFileName);
Console.Read();
}
static void SaveObjectAsXmlFormat(object objGraph, string fileName)
{
// Save object to a file in XML format.
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamWriter writer = new StreamWriter(fileName))
{
Console.WriteLine("<<Starting serializing>>");
xmlFormatter.Serialize(writer, objGraph);
Console.WriteLine(objGraph.ToString());
}
}
static void DeserializeObjectFromXMLFormat(object objGraph, string filename)
{
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using (StreamReader reader = new StreamReader(filename))
{
Console.WriteLine("<<starting deserializing>>");
MyLuxuryCar myCar = (MyLuxuryCar)xmlFormatter.Deserialize(reader);
Console.WriteLine(myCar.ToString());
}
}
}
[Serializable]
public class Radio
{
public bool hasMicrophonePoint;
public bool hasSubwoofers;
public double[] playStations;
[NonSerialized]
public string stationID = "FM-88.9_Radio Foorti";
}
[Serializable]
public class Car
{
public Radio radio = new Radio();
[XmlIgnore]
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
[XmlAttribute(AttributeName="ModelName")]
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo, hasAutomaticWeaponSystem);
}
}
[Serializable, XmlRoot(Namespace = "https://mushfiqrazib.wordpress.com")]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
[XmlAttribute(AttributeName="CanFly")]
public bool CanJump;
[XmlAttribute(Namespace="http://www.mushfiqrazib.com")]
public bool hasWaterProofSystem;
}

Basics of XML Serialization /Deserialization

Standard

XML Serialization
With XML serialization, the public state of objects can be converted into an XML document. Such XML information is often stored on disk to persist data for later use, or is transported over a network or the Internet to send messages between computers.

Serialization Process

In this article I will demonstrate the basics of XML serialization. In the previous 2 articles [Binary Serialization / Deserialization and Serializing/Deserializing Using the SoapFormatter]  binary and soap formatter has been discussed. The System.Xml.dll assembly provides a third formatter System.Xml.Serialization.XmlSerializer. This formatter allows to persist the public state of a given object as pure XML, as opposed to XML data wrapped within a SOAP message and later deserialized back into objects.

The main advantage of XML serialization over binary serialization is portability. XML can be interpreted using many development frameworks and languages, and on computers using a variety of operating systems. This allows to send the XML representation of an object to software applications that are not using the .NET framework or Microsoft Windows. In addition, XML is human-readable and editable, allowing serialized information to be modified using a standard text editor such as Notepad.

There are two key drawbacks of XML serialization.

  • Firstly, only the public state of objects is serialized. Private fields and properties are not represented in the produced XML.
  • Secondly, object references are not maintained when the XML is deserialized into an object; if the original object contained two references to the same object, the deserialization process will generate references to two separate objects.

In the previous 2 articles, I use the MyLuxuryCar sample code which is now also will be used here. The difference is that instead of saving the file in binary or soap file, we will save the object state information in a xml file. For this we need the System.IO namespace. To simplify the code for all of the classes used, following using directives are added to the code file.
using System.IO;
using System.Xml.Serialization;

In the following Main() method SaveObjectAsXmlFormat and DeserializeObjectFromXMLFormat methods are used for serialization and deserialization respectively.
To perform XML serialization on the MyLuxuryCar object, an instance of the XmlSerializer is created.The key difference with the other two (binary and soap) serialization technique is that the XmlSerializer type requires to specify type information that represents the class to serialize. This can be provided as a parameter to the constructor of the XmlSerializer instantiation. Add the following code to create a serializer for the MyLuxuryCar class:

XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());

Next we need a target for the generated XML. This can be a stream, a TextWriter, an XmlWriter or a subclass of one of these types. In the example code we will serialize to a file using a StreamWriter. Note that the path for the new file is passed into the constructor. Add the below code:

// Save object to a file in XML format.
using(StreamWriter writer = new StreamWriter(fileName))
{
Console.WriteLine("<<<Starting Serializing using XmlSerializer >>>");
xmlFormatter.Serialize(writer, objGraph);
Console.WriteLine(objGraph.ToString());
}

Inside the using snippet, after the stream writer is ready i.e. writer object is created, the XmlSerializer object i.e. xmlFormatter calls the serialize method which accepts two arguments. The first is stream and other one is the object being serialized. The xml file of the persisting object state information will be look like the below:

<?xml version=”1.0″ encoding=”utf-8″?>
<MyLuxuryCar xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
             xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;
  <radio>
    <hasMicrophonePoint>true</hasMicrophonePoint>
    <hasSubwoofers>true</hasSubwoofers>
    <playStations>
      <double>88</double>
      <double>89.6</double>
      <double>100.2</double>
      <double>99.8</double>
    </playStations>
    <stationID>FM-88.9_Radio Foorti</stationID>
  </radio>
  <hasAutomaticWeaponSystem>true</hasAutomaticWeaponSystem>
  <Model>Ferrari</Model>
  <Color>Black</Color>
  <CanJump>true</CanJump>
  <hasWaterProofSystem>true</hasWaterProofSystem>
</MyLuxuryCar>

Deserializing From XML

The deserialization process uses an XmlSerializer object that is created in exactly the same manner as for serialization. To convert the XML from a stream, TextReader or XmlReader to an object, you call the Deserialize method. This method returns a basic object, which can be cast to the appropriate type.
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using(StreamReader reader = new StreamReader(filename))
{
Console.WriteLine("<<<Starting Deserializing object>>>");
MyLuxuryCar myCar = (MyLuxuryCar)xmlFormatter.Deserialize(reader);
Console.WriteLine(myCar.ToString());
}

Important to note that the XmlSerializer demands that all serialized types in the object graph support a default constructor (so be sure to add it back if any custom constructors are defined). If this is not the case, then an InvalidOperationException will raise at runtime.

The full code snippet is given below:
public class SerializationTest
{
private static void Main(string[] args)
{
string PersistingXMLFileName = "MyLuxuryFerrari.xml";
Car myCar = new MyLuxuryCar(true,true);
myCar.Color = "Black";
myCar.Model = "Ferrari";
myCar.hasAutomaticWeaponSystem = true;
myCar.AddMiles(2000);
myCar.AddCrashes(5);
myCar.radio.hasSubwoofers = true;
myCar.radio.playStations = new double[] {88.0, 89.6, 100.2, 99.8};
myCar.radio.hasMicrophonePoint = true;
// Serialize myCar object.
SaveObjectAsXmlFormat(myCar, PersistingXMLFileName);
// Deserialize myCar object from the XML file
DeserializeObjectFromXMLFormat(myCar, PersistingXMLFileName);
Console.Read();
}
static void SaveObjectAsXmlFormat(object objGraph, string fileName)
{// Save object to a file in XML format.
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using(StreamWriter writer = new StreamWriter(fileName))
{
Console.WriteLine("<<<Starting Serializing using XmlSerializer >>>");
xmlFormatter.Serialize(writer, objGraph);
Console.WriteLine(objGraph.ToString());
}
}
static void DeserializeObjectFromXMLFormat(object objGraph, string filename)
{
XmlSerializer xmlFormatter = new XmlSerializer(objGraph.GetType());
using(StreamReader reader = new StreamReader(filename))
{
Console.WriteLine("<<<Starting Deserializing object>>>");
MyLuxuryCar myCar = (MyLuxuryCar)xmlFormatter.Deserialize(reader);
Console.WriteLine(myCar.ToString());
}
}
}
[Serializable]
public class Radio
{
public bool hasMicrophonePoint;
public bool hasSubwoofers;
public double[] playStations;
[NonSerialized]
public string stationID = "FM-88.9_Radio Foorti";
}
[Serializable]
public class Car
{
public Radio radio = new Radio();
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo, hasAutomaticWeaponSystem);
}
}
[Serializable]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
public bool CanJump;
public bool hasWaterProofSystem;
}

XML serialization using the .NET framework supports many configuration options that allow the exact structure of the XML to be controlled. However, in this article I  only used the default settings for serialization. In future articles we will see how to customise the process further, including changing the names of the XML attributes and elements that are created and using XML schemas.

Serializing/Deserializing Using the SoapFormatter

Standard

In this article i will use the SoapFormatter type, which serializes data in a proper SOAP envelope. In a nutshell, the Simple Object Access Protocol (SOAP) defines a standard process in which we can invoke methods in a platform- and OS-neutral manner.

SOAP Serialization

XML serialization can also be used to serialize objects into XML streams that conform to the SOAP specification. SOAP is a protocol based on XML, designed specifically to transport procedure calls using XML. As with regular XML serialization, attributes can be used to control the literal-style SOAP messages generated by an XML Web service.

Serialization Process:

In the sample code, we will serialize an object and store the resultant information in a SOAP format file. This uses functionality from the System.IO namespace. To simplify the code for all of the classes used, following using directives are added to the code file.

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

The two key methods of the SoapFormatter type are Serialize() and Deserialize():
• Serialize(): Persists an object graph to a specified stream as a SOAP message.
• Deserialize(): Converts a SOAP message to an object graph.

Assume we need to create an instance of MyLuxuryCar, modified some state data, and want to persist car information into a *.soap file. Begin by creating the *.soap file itself. We can achieve this by creating an instance of the System.IO.FileStream type. At this point, we can create an instance of the SoapFormatter and pass in the FileStream and object graph to persist.

Consider the following Main() method where for serialization SaveObjectAsSOAPFormat and for deserialization DeserializeObjectFromSOAPFormat methods are used. We need a formatter to perform serialization on the MyLuxuryCar object.  Formatters are responsible for converting objects to serialized information and they implement the IFormatter interface. To create a Soap formatter, add the following line of code:

IFormatter soapFormatter = new SoapFormatter();
Formatter sent the data to a stream and FileStream is used to store the stream data into a file. As FileStream uses IDisposable interface, we have to call Dispose method as soon as the process finished. So for that, using has been used to dispose the fstream object automatically. Add the below code:
IFormatter soapFormatter = new SoapFormatter();
using (FileStream fstream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Console.WriteLine("<<<Starting Serializing using SOAP formatter >>>");
//Persists an object graph to a specified stream as a sequence of bytes
soapFormatter.Serialize(fstream, objGraph);
Console.WriteLine(objGraph.ToString());
}

Inside the using snippet, after the stream is ready i.e. fstream object is created, the formatter calls the serialize method which accepts two arguments. The first is stream and other one is the object being serialized.

For deserialization, we just read the object information from the persisting file (MyLuxuryFerrari.soap) and convert the soap message data again into the MyLuxuryCar object file using the below code snippet:

   IFormatter soapFormatter = new SoapFormatter();
using (FileStream fstream = File.OpenRead(filename))
{
Console.WriteLine("<<<Starting Deserializing object>>>");
MyLuxuryCar myCar = (MyLuxuryCar)soapFormatter.Deserialize(fstream);
Console.WriteLine(myCar.ToString());
}

 Note that while using Deserialize method of the formatter, we have to cast the fstream data into the desired object, here MyLuxuryCar object.

The full code snippet is given below:
public class SerializationTest
{
private static void Main(string[] args)
{
string PersistingSOAPFileName = "MyLuxuryFerrari.soap";
Car myCar = new MyLuxuryCar(true,true);
myCar.Color = "Black";
myCar.Model = "Ferrari";
myCar.hasAutomaticWeaponSystem = true;
myCar.AddMiles(2000);
myCar.AddCrashes(5);
myCar.radio.hasSubwoofers = true;
myCar.radio.playStations = new double[] {88.0, 89.6, 100.2, 99.8};
myCar.radio.hasMicrophonePoint = true;
// Serialize myCar object.
SaveObjectAsSOAPFormat(myCar, PersistingSOAPFileName);
// Deserialize myCar object from the SOAP file
DeserializeObjectFromSOAPFormat(PersistingSOAPFileName);
Console.Read();
}
static void SaveObjectAsSOAPFormat(object objGraph, string filename)
{
IFormatter soapFormatter = new SoapFormatter();
using (FileStream fstream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Console.WriteLine("<<<Starting Serializing using SOAP formatter >>>");
//Persists an object graph to a specified stream as a sequence of bytes
soapFormatter.Serialize(fstream, objGraph);
Console.WriteLine(objGraph.ToString());
}
}
static void DeserializeObjectFromSOAPFormat(string filename)
{
IFormatter soapFormatter = new SoapFormatter();
using (FileStream fstream = File.OpenRead(filename))
{
Console.WriteLine("<<<Starting Deserializing object>>>");
MyLuxuryCar myCar = (MyLuxuryCar)soapFormatter.Deserialize(fstream);
Console.WriteLine(myCar.ToString());
}
}
}
[Serializable]
public class Radio
{
public bool hasMicrophonePoint;
public bool hasSubwoofers;
public double[] playStations;
[NonSerialized]
public string stationID = "FM-88.9_Radio Foorti";
}
[Serializable]
public class Car
{
public Radio radio = new Radio();
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo,hasAutomaticWeaponSystem);
}
}
[Serializable]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
public bool CanJump;
public bool hasWaterProofSystem;
}

Once run the program, we can view the contents of the MyLuxuryFerrari.soap file that represents this instance of the MyLuxuryCar by navigating to the \bin\Debug folder of the current project.

The figure below showst the persisting file i.e. MyLuxuryFerrari.soap, which contains the object states information:

File that contains object information after the Soap serialization

File that contains object information after the Soap serialization

Binary Serialization / Deserialization

Standard

Binary Serialization

A standard problem with object-oriented languages is that of persisting object state. Binary serialization allows single objects or complex models to be converted to binary streams, which may be stored in files or transported to other systems.

Serialization Process:

In the sample code, we will serialize an object and store the resultant information in a file. This uses functionality from the System.IO namespace. To simplify the code for all of the classes used, following using directives are added to the code file.

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

 The two key methods of the BinaryFormatter type are Serialize() and Deserialize():
• Serialize(): Persists an object graph to a specified stream as a sequence of bytes.
• Deserialize(): Converts a persisted sequence of bytes to an object graph.

Assume we need to create an instance of MyLuxuryCar, modified some state data, and want to persist car information into a *.dat file. Begin by creating the *.dat file itself. We can achieve this by creating an instance of the System.IO.FileStream type. At this point, we can create an instance of the BinaryFormatter and pass in the FileStream and object graph to persist.

Consider the following Main() method where for serialization SaveObjectAsBinaryFormat and for deserialization DeserializeObjectFromBinaryFormat methods are used. We need a formatter to perform serialization on the MyLuxuryCar object.  Formatters are responsible for converting objects to serialized information and they implement the IFormatter interface. To create a binary formatter, add the following line of code:

IFormatter binary = new BinaryFormatter();

Formatter sent the data to a stream and FileStream is used to store the stream data into a file. As FileStream uses IDisposable interface, we have to call Dispose method as soon as the process finished. So for that, using has been used to dispose the fstream object automatically. Add the below code:

using (FileStream fstream =
new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Console.WriteLine("<<<Starting Serializing - using Binary Formatter>>>");
//Persists an object graph to a specified stream as a sequence of bytes
binary.Serialize(fstream, objGraph);
Console.WriteLine(objGraph.ToString());
}

 Inside the using snippet, after the stream is ready i.e. fstream object is created, the formatter calls the serialize method which accepts two arguments. The first is stream and other one is the object being serialized.

For deserialization, we just read the object information from the persisting file (MyLuxuryFerrari.dat) and convert the binary data again into the MyLuxuryCar object file using the below code snippet:

IFormatter binary = new BinaryFormatter();
using (FileStream fstream = File.OpenRead(filename))
{
Console.WriteLine("<<<Starting Deserializing object>>>");
//Converts a persisted sequence of bytes to an object graph.
MyLuxuryCar myCar = (MyLuxuryCar)binary.Deserialize(fstream);
Console.WriteLine(myCar.ToString());
//Console.WriteLine("Can my car Jump: {0}", myCar.CanJump);
}

Note that while using Deserialize method of the formatter, we have to cast the fstream data into the desired object, here MyLuxuryCar object.

 The full code snippet is given below:

[Serializable]
public class Radio
{
public bool hasMicrophonePoint;
public bool hasSubwoofers;
public double[] playStations;
[NonSerialized]
public string stationID = "FM-88.9_Radio Foorti";
}
[Serializable]
public class Car
{
public Radio radio = new Radio();
public bool hasAutomaticWeaponSystem;
private int crashesNo = 0;
private int RunningMiles = 50;
public string Model { get; set; }
public string Color { get; set; }
public void AddCrashes(int crashes)
{
crashesNo += crashes;
}
public void AddMiles(int miles)
{
RunningMiles += miles;
}
public override string ToString()
{
return String.Format(@"Car Info: Model -> {0}, Color -> {1}, Traveling -> {2}, Crash(es) - > {3},
Weapon System -> {4}", Model, Color, RunningMiles, crashesNo, hasAutomaticWeaponSystem);
}
}
[Serializable]
public class MyLuxuryCar : Car
{
public MyLuxuryCar() { }
public MyLuxuryCar(bool canJump, bool isWaterProof)
{
CanJump = canJump;
hasWaterProofSystem = isWaterProof;
}
public bool CanJump;
public bool hasWaterProofSystem;
}
public class SerializationTest
{
private static void Main(string[] args)
{
string PersistingFileName = "MyLuxuryFerrari.dat";
Car myCar = new MyLuxuryCar(true,true);
myCar.Color = "Black";
myCar.Model = "Ferrari";
myCar.hasAutomaticWeaponSystem = true;
myCar.AddMiles(2000);
myCar.AddCrashes(5);
myCar.radio.hasSubwoofers = true;
myCar.radio.playStations = new double[] {88.0, 89.6, 100.2, 99.8};
myCar.radio.hasMicrophonePoint = true;
// Serialize myCar object.
SaveObjectAsBinaryFormat(myCar, PersistingFileName);
// Deserialize myCar object from the binary file
DeserializeObjectFromBinaryFormat(PersistingFileName);
Console.Read();
}
static void SaveObjectAsBinaryFormat(object objGraph, string filename)
{
IFormatter binary = new BinaryFormatter();
using (FileStream fstream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Console.WriteLine("<<<
Starting Serializing - using Binary Formatter>>>”);
//Persists an object graph to a specified stream as a sequence of bytes
binary.Serialize(fstream, objGraph);
Console.WriteLine(objGraph.ToString());
}
}
static void DeserializeObjectFromBinaryFormat(string filename)
{
IFormatter binary = new BinaryFormatter();
using (FileStream fstream = File.OpenRead(filename))
{
Console.WriteLine(“<<<Starting Deserializing object>>>”);
//Converts a persisted sequence of bytes to an object graph.
MyLuxuryCar myCar = (MyLuxuryCar)binary.Deserialize(fstream);
Console.WriteLine(myCar.ToString());
//Console.WriteLine(“Can my car Jump: {0}”, myCar.CanJump);
}
}
}

Once run the program, we can view the contents of the MyLuxuryFerrari.dat file that represents this instance of the MyLuxuryCar by navigating to the \bin\Debug folder of the current project.

The figure below showst the persisting file i.e. MyLuxuryFerrari.dat, which contains the object states information:

File that contains object information after the binary serialization

File that contains object information after the binary serialization

Exposing .NET Serialization

Standard

What is Serialization in .NET?

Serialization is the process of converting an object into a stream of bytes in order to persist (possibly transferring) it to memory, a databases or a file. Its main purpose is to save the state of an object into a stream (e.g., file stream and memory stream).The persisted data sequence contains all the necessary information to reconstruct (or deserialize) the state of the object for use later, this process is called deserialization. Using this technology makes it trivial to save vast amounts of data (in various formats).

How Serialization Works
How Serialization Works

The object is serialized to a stream, which carries not just the data, but information about the object’s type, such as its version, culture, and assembly name. From that stream, it can be stored in a database, a file, or memory.

Uses for Serialization
Serialization allows the developer to save the state of an object and recreate it as needed, providing storage of objects as well as data exchange. Some uses of serialization/deserialization include:

1. sending the object to a remote application by means of a Web Service.
2. passing an object from one domain to another
3. passing an object through a firewall as an XML string
4. maintaining security or user-specific information across applications.

Making an Object Serializable

 Generally, to serialize an object:
– first need the object to be serialized [using System.Runtime.Serialization namespace]
– A stream to contain the serialized object [using System.IO namespace]
– A Formatter [For binary serialization System.Runtime.Serialization.Formatters.Binary namespace]
To do the above 3 things properly, there are some issues which have to take care while doing the serialization of an object. Those are given below:

1. Using Serializable Type:

System.Runtime.Serialization contains the classes necessary for serializing and deserializing objects.Apply the SerializableAttribute attribute to a type to indicate that instances of this type can be serialized. If a class has some field which do not need to be serializable, apply the NonSerializedAttribute attribute. If a serialized class contains references to objects of other classes that are marked SerializableAttribute, those objects will also be serialized. For example, let see the Radio class defined below.

[Serializable]
public class Radio
{
public bool hasMicrophonePoint;
public bool hasSubwoofers;
public double[] playStations;
[NonSerialized]
public string stationID = "FM-88.9_Radio Foorti";
}

Radio class has been marked[Serializable], excluding a single member variable (stationID) that has been marked [NonSerialized] and will therefore not be persisted into the specified data stream.

2. Taking care of Object Graphs:

In .Net while serializing an object, the state of that object is persisted into a stream with all the associated data i.e. base class data and contained objects which are also serialized as well. Therefore, to persists a derive class, all data up to the chain of inheritance will also come along the way. This is the task of CLR who ensure that all related objects are persisted while an object is serialized. This set of related objects called ‘object graph’.

Now, defining a base Car class and then MyCar class which inherits the base Car class. Both the classes are marked with [Serializable] attribute.

[Serializable]
public class Car
{
public Radio radio = new Radio();
public bool hasAutomaticWeaponSystem;
}
[Serializable]
public class MyCar : Car
{
public MyCar() { }
public MyCar(bool canJump, bool iswaterProof)
{
CanJump = canJump;
hasWaterProofSystem = iswaterProof;
}
public bool CanJump;
public bool hasWaterProofSystem;
}

One thing is to note here that we cannot inherit the [Serializable] attribute from base class. So, if a class is derived from a base class which is marked as [Serializable], the child class must also be marked [Serializable] as well or it cannot be persisted. In fact, all objects in an object graph must be marked with the [Serializable] attribute. If we attempt to serialize a non-serialize object using the BinaryFormatter or SoapFormatter, a SerializationException will receive in runtime.

3. Public, Private fields and Public properties
[Serializable]
public class Person
{
public Person() { }
private string fname;
private string lname;
private string nid;
public bool HasPassport;
public bool IsMarried;
public string Address;
public string FirstName
{
get { return fname; }
set { fname = value; }
}
}

How the various formatter’s expect a type’s field data to be defined in order to be serialized into a stream? The answer is that it depends. If an object’s state is persisting using the BinaryFormatter or SoapFormatter, it makes no difference whether the fields are public, private or private fields exposed through public properties. So, if above code is processed by BinaryFormatter or SoapFormatter then all the public and private fields and properties are saved into the selected stream.
However, the situation is different in case of XmlSerialization. This type will only serialize public data fields or private data exposed by public properties. Private data not exposed from properties will be ignored. If the code example is serialized using the XmlSerializer then it would not save the value of ‘lname’ and ‘nid’ because these pieces of private data are not encapsulated by public properties. To persist the ‘lname’ field with the XmlSerializer, either the field must be public or encapsulated that private member (personAge) using a public property like the FirstName property which exposes the private member ‘fname’.

4. Serialization Formatter in .NET

In .NET serialization, 3 types of format (binary, SOAP, XML) are used to persist the object’s state. The 3 classes which are responsible for this are given below:

BinaryFormatter – serializes object’s state to a stream using a compact binary format. This type is defined within the System.Runtime.Serialization.Formatters.Binary namespace that is part of mscorlib.dll.

SoapFormatter – persists an object’s state as a SOAP message (the standard XML format for passing messages to/from a web service). This type is defined within the System.Runtime.Serialization.Formatters.Soap namespace, which is defined in a separate assembly i.e. System.Runtime.Serialization.Formatters.Soap.dll

XmlSerializer – persist a tree of objects as an XML document. System.Xml.Serialization namespace defined this type and belongs to System.Xml.dll assembly.

5. Type fidelity among the formatters:

When using the BinaryFormatter type, it will persist not only the field data of the objects in the object graph, but also each type’s fully qualified name and the full name of the defining assembly i.e. assembly name, version, public key token and culture. These extra points of data make the BinaryFormatter an ideal choice to transport objects by value (e.g., as a full copy) across machine boundaries for .NET-centric applications. If the Person class is serialized using BinaryFormatter, then the persisting person object file (Person.dat) will be like the figure below. From the figure it shows that the right side of the figure describes the fully qualified name of the assembly.

Binary Serialization type fidelity

Binary Serialization type fidelity

The SoapFormatter persists traces of the assembly of origin through the use of an XML namespace. For example, if the Person type is persisted as a SOAP message, then opening element of Person is qualified by the generated xmlns like the below soap message. See the a1 XML namespace:

<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/&#8221;
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/&#8221;
xmlns:clr=”http://schemas.microsoft.com/soap/encoding/clr/1.0&#8243;
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”&gt;
<SOAP-ENV:Body>
<a1:Person id=”ref-1″
xmlns:a1=”http://schemas.microsoft.com/clr/nsassem/C.Sharp.Code.Gallery.Serialization/
C.Sharp.Code.Gallery.Serialization%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull”>
<fname xsi:null=”1″/>
<lname xsi:null=”1″/>
<nid xsi:null=”1″/>
<HasPassport>false</HasPassport>
<IsMarried>false</IsMarried>
<Address xsi:null=”1″/>
</a1:Person>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

However, the XmlSerializer does not attempt to preserve full type fidelity; therefore, it does not record the type’s fully qualified name or assembly of origin. This might seem like a limitation at first glance, but XML serialization is used by classic .NET web services, which can be called from clients on any platform (not just .NET). This means that there is no point serializing full .NET type metadata. Here is a possible XML representation of the Person type:

<?xml version=”1.0″?>
<Person xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;
<HasPassport>false</HasPassport>
<IsMarried>false</IsMarried>
</Person>

To persist an object’s state in a manner that can be used by any operating system (e.g.,Windows XP, Mac OS X, and various Linux distributions), application framework (e.g., .NET, Java Enterprise Edition, and COM), or programming language, then it would not necessary to maintain full type fidelity because  it is not possible to assume all possible recipients can understand .NET-specific data types. Given this, SoapFormatter and XmlSerializer are ideal choices when you wish to ensure as broad a reach as possible for the persisted tree of objects.

6. The IFormatter and IRemotingFormatter Interfaces

All the formatter in .net derive directly from System.Object. So, they do not share a common set of members from a serialization-centric base class.
However, the BinaryFormatter and SoapFormatter types do support common members through the implementation of the IFormatter and IRemotingFormatter interfaces (strange as it might seem, the XmlSerializer implements neither).

System.Runtime.Serialization.IFormatter defines the core Serialize() and Deserialize() methods, which do the grunt work to move your object graphs into and out of a specific stream. Beyond these members, IFormatter defines a few properties that the implementing type uses behind the scenes:

public interface IFormatter
{
SerializationBinder Binder { get; set; }
StreamingContext Context { get; set; }
ISurrogateSelector SurrogateSelector { get; set; }
object Deserialize(Stream serializationStream);
void Serialize(Stream serializationStream, object graph);
}

The System.Runtime.Remoting.Messaging.IRemotingFormatter interface (which is leveraged internally by the .NET remoting layer) overloads the Serialize() and Deserialize() members into a manner more appropriate for distributed persistence. Note that IRemotingFormatter derives from the more general IFormatter interface:

public interface IRemotingFormatter : IFormatter
{
object Deserialize(Stream serializationStream, HeaderHandler handler);
void Serialize(Stream serializationStream, object graph, Header[] headers);
}

Although it does not need to interact directly with these interfaces for most of the serialization endeavors, recall that interface-based polymorphism allows to hold an instance of BinaryFormatter or SoapFormatter using an IFormatter reference. Therefore, to build a method that can serialize an object graph using either of these classes, one could write the following:

static void SerializeObjectGraph(IFormatter itfFormat, Stream destStream, object graph)
{
itfFormat.Serialize(destStream, graph);
}

Binary and XML Serialization
Either binary or XML serialization can be used. In binary serialization, all members, even those that are read-only, are serialized, and performance is enhanced. XML serialization provides more readable code, as well as greater flexibility of object sharing and usage for interoperability purposes.

Binary Serialization
Binary serialization uses binary encoding to produce compact serialization for uses such as storage or socket-based network streams.

XML Serialization
XML serialization serializes the public fields and properties of an object, or the parameters and return values of methods, into an XML stream that conforms to a specific XML Schema definition language (XSD) document. XML serialization results in strongly typed classes with public properties and fields that are converted to XML. System.Xml.Serialization contains the classes necessary for serializing and deserializing XML.

SOAP Serialization
XML serialization can also be used to serialize objects into XML streams that conform to the SOAP specification. SOAP is a protocol based on XML, designed specifically to transport procedure calls using XML. As with regular XML serialization, attributes can be used to control the literal-style SOAP messages generated by an XML Web service.

References:

1. Serialization (C# and Visual Basic)