Click here to Skip to main content
Click here to Skip to main content

Serialization using different formats in .NET

, 16 Jul 2012
Rate this:
Please Sign up or sign in to vote.
How to do serialization using different formats in .NET.

Introduction

Serialization is the process of converting an object in to bytes for persistence storage. The deserialization process converts the bytes to object without any loss of data. Serialization is used for storing values in files or database, send an object through the network and to convert back to the original object format. The .NET Framework provide a set of Framework Class Libraries (FCL) for making the serialization process easy. It is very useful for sending data between two different applications. 

The .NET Framework supports binary serialization and XML serialization formats. XML serialization serializes only public fields. But, binary serialization will serialize all private and public fields. Serialization can be performed either as basic or custom. Basic serialization happens when a class has the SerializableAttribute attribute applied. Basic serialization doesn't support for versioning. A custom serialization class must be marked SerializableAttribute and implement the ISerializable interface. The user can implement custom serialization for both Binary and XML serialization formats. GetObjectData needs to be overridden for a custom application. The sample application uses custom serialization for both binary and XML serialization. The .NET Framework supports designer serialization which is associated with development tools.

Custom serialization

Custom serialization is the process of controlling the serialization and deserialization process. Custom serialization can be implemented by running custom methods during and after serialization or by implementing the ISerializable interface. Custom serialization is used for versioning the serialization object. If the serialized object has changed the object state (added a new file in later version), custom serialization is used for getting the values without loss of data. The versioning of the serialized object may fail due to missing attributes.

If the user wants to use custom methods during and after serialization, the user should apply the custom serialization support using OnDeserializedAttribute, OnDeserializingAttribute, OnSerializedAttribute and OnSerializingAttribute attributes for customizing the data during serialization and deserialization. The OptionalFieldAttribute attribute is used for ignoring the old version data for deserialization. The formatter doesn't give any error during deserialization. It allows for updating the object before and after serialization/deserialization.

The following code explains the usage of the serializing attributes:

[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context)
{
// Update member during Serializing
}
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context)
{
// Update member after Serialized
}
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context)
{
// Update member during Deserializing
}
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context)
{
// Update member after Deserialized
}

If the user wants to implement ISerializable, the serializing class should always implement the ISerializable interface with the Serializable attribute. ISerializable involves implementing the GetObjectData method and a special constructor that is used when the object is deserialized.

[Serializable]
public class Employee : ISerializable
{
public int age;
public string name;
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("Null info Object");
info.AddValue("EmployeeName", name);
info.AddValue("EmployeeAge", age);
}
public Employee(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("Null info Object");
name = (string)info.GetValue("EmployeeName", typeof(string));
age = (int)info.GetValue("EmployeeAge", typeof(int));
}
}

Binary format serialization

Binary serialization is used for serializing an object which uses network steams, or convert a WCF object type and store in the file system. Binary serialization is used to get data back from a network stream and other types without any loss. The binary object can be serialized to disk, memory, network, etc. The class public and private members are serialized and restored back as the original value in the deserialization process. This process is used to store large object values in persistence storage or to send them through a network and restore back when required. The serialization process is useful when a large object has to be stored in persistence storage. The object oriented class hierarchy may involve complexity for storing and retrieving values. This process is useful for resolving complexities automatically. The Common Language Runtime will manage the object reference and circular references between classes automatically. 

The serializing class is requires to make use of the Serializable attribute. The BinaryFormatter class from the System.Runtime.Serialization.Formatters.Binary namespace is used for serializing and deserializing objects in binary format. When a class needs to be serialized, the instance of the stream needs to be sent to the Serialize method in the formatter class. 

Binary serialization uses binary format for understanding communication between .NET Framework applications. It saves metadata information along with an object. It helps for restructuring the object when it deserializes an object from persistence storage. A binary formatter is faster than other serialization formatters. It can serialize generic and non-generic collections. This serialization supports serializing private and public members.

static void Serialize(Employee emp, string filename)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
Console.WriteLine("Writing Employee Information");
try
{
bformatter.Serialize(stream, emp);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Serialization data : " + ex.Message);
throw;
}
finally
{
stream.Close();
Console.WriteLine("successfully wrote Employee information");
}
}
static void Deserialize(string filename)
{
Employee mp = null;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
Console.WriteLine("Reading Employee Information");
try
{
mp = (Employee)bformatter.Deserialize(stream);
Thread.Sleep(500);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Deserialize data : " + ex.Message);
throw;
}
finally
{
stream.Close();
}
if (mp != null)
{
Console.WriteLine("Employee Name: {0}", mp.Name);
Console.WriteLine("Employee Password: {0}", mp.SystemPassword);
Console.WriteLine("Employee Id: {0}", mp.Age.ToString());
}
else
{
Console.WriteLine("Deserialize Employee null value");
}
}

Some class members may not include the details for serialization. For example, when a program collects data for storing, the login information should not store the password or any sensitive information like credit card details. So the user will not want to store those values in persistence storage. If a field must not be serialized, the field should be mark with the NonSerialized attribute. Otherwise, the code has permission to expose all the sensitive data when it has permission for deserializing the data.

[Serializable] public class Employee {
public int age;
public string name;
[NonSerialized()]
public string systempassword;
}

When the class is not marked as Serializable, the following exception is thrown.

Serializable Exception

If the base class is serialized using the Serializable attribute the derived class also should be marked with the Serializable attribute. If not when the user serializes the derived class, it will throw the SerializationException. The exception message explains the derived class wasn't marked with the Serializable attribute. The object life time is available only within the domain. But when the object is derived from MarshalByRefObject or marked as Serializable, it can be shared between application domains. The object can be serialized from one domain and deserialized from another domain without any data loss. An object derived from MarshalByRefObject will pass the reference instead of passing the values between the application domains.

XML and SOAP serialization

XML format serialization using XmlSerializer

The XmlSerializer class is derived directly from the Object base class. XML serialization does not include type information. XML serialization serializes only public fields and properties of the object into an XML stream that confirms with the specific XSD language. The System.Xml.Serialization namespace has all the classes and interfaces for serializing and deserializing values. SOAP serialization confirms to the SOAP specification. Web applications can use the XmlSerializer class to create XML and send across applications. XML serialization converts only public fields and properties of an object into the XML stream.

XML serialization uses XmlSerializer for serializing and deserializing a type of the object with StreamWriter. XML serialization also requires the Serializable attribute for serializing an object. The object must implement a parameter less constructor. It can serialize generic and non-generic collections. The user can control the fields using [XmlAttribute], [XmlIgnore], and [XmlElement (ElementName="NewName"] attributes.

The programming language constructs class, fields, property, arrays can be exposed with XmlAttribute or XmlElement. The XmlSerializer class can also serialize a SOAP encoded XML stream. The public properties and fields, classes implement ICollection or IEnumerable. XmlElement, XmlNode, and DataSet can be serialized.

static void Serialize(Employee emp, string filename)
{
XmlSerializer mySerializer = new XmlSerializer(typeof(Employee));
StreamWriter stream = new StreamWriter(filename);
Console.WriteLine("Writing Employee Information");
try
{
mySerializer.Serialize(stream, emp);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Serialization data : " + ex.Message);
throw;
}
finally
{
stream.Close();
Console.WriteLine("successfully wrote Employee information");
}
}
static void Deserialize(string filename)
{
Employee mp = null;
XmlSerializer mySerializer = new XmlSerializer(typeof(Employee));
FileStream myFileStream = new FileStream(filename, FileMode.Open);
Console.WriteLine("Reading Employee Information");
try
{
mp = (Employee)mySerializer.Deserialize(myFileStream);
Thread.Sleep(500);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Deserialize data : " + ex.Message);
throw;
}
finally
{
myFileStream.Close();
}
if (mp != null)
{
Console.WriteLine("Employee Name: {0}", mp.Name);
Console.WriteLine("Employee Id: {0}", mp.Age.ToString());
}
else
{
Console.WriteLine("Deserialize Employee null value");
}
}

XmlObjectSerializer

The XmlObjectSerializer class is used to serialize objects as XML streams or documents. The DataContractSerializer class is derived from XmlObjectSerializer. XmlObjectSerializer is an abstract class. So the user cannot directly use this class.

SOAP format serialization using SoapFormatter

SoapFormatter is used for serializing and deserializing an object or an entire graph of connected objects. Since .NET Framework 2.0, the user can use either BinaryFormatter or SoapFormatter. The SOAP formatter is useful when more than one type of application communicates with each other. The SOAP formatter is useful when a Java app communicates with a .NET application using SOAP standard specification. It also copies private and public members. SOAP is an XML based protocol used for transport. It cannot serialize generic collections. The attributes SoapAttributeAttribute, SoapElementAttribute, SoapEnumAttribute, SoapIgnoreAttribute, SoapIncludeAttribute, and SoapTypeAttribute control encoded SOAP serialization.

static void Serialize(Employee emp, string filename)
{
FileStream fs = new FileStream(filename, FileMode.Create);
SoapFormatter formatter = new SoapFormatter();
Console.WriteLine("Writing Employee Information");
try
{
formatter.Serialize(fs, emp);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Serialization data : " + ex.Message);
throw;
}
finally
{
fs.Close();
Console.WriteLine("successfully wrote Employee information");
}
}
static void Deserialize(string filename)
{
Employee mp = null;
FileStream fs = new FileStream(filename, FileMode.Open);
Console.WriteLine("Reading Employee Information");
try
{
SoapFormatter formatter = new SoapFormatter();
mp = (Employee)formatter.Deserialize(fs);
Thread.Sleep(500);
}
catch (SerializationException ex)
{
Console.WriteLine("Exception for Deserialize data : " + ex.Message);
throw;
}
finally
{
fs.Close();
}
if (mp != null)
{
Console.WriteLine("Employee Name: {0}", mp.Name);
Console.WriteLine("Employee Id: {0}", mp.Age.ToString());
}
else
{
Console.WriteLine("Deserialize Employee null value");
}
}

Data Contract Serialization

Data contract serialization uses DataContractAttribute, DataMemberAttribute, DataContractSerializer, and NetDataContractSerializer attributes for serialization.

DataContractSerializer is faster than XmlSerializer. WCF proxy classes use XmlSerializer when DataContractSerializer is not supported.

[DataContract]
class Employee {
[DataMember(Name = "EmployeeName")]
internal string Name;
[DataMember(Name = "EmployeeAge")]
internal int Age;
public Employee(string newName, int newAge)
{
Name = newName;
Age = newAge;
}
}
class Program
{
public static void Main()
{
Employee p1 = new Employee("Sivaselvi", 22);
XmlDictionaryWriter writer = null;
FileStream fs = null;
DataContractSerializer ser = null;
// Write the object to Employee.xml
try
{
fs = new FileStream("Employee.xml", FileMode.Create);
writer = XmlDictionaryWriter.CreateTextWriter(fs);
DataContractSerializer ser = new DataContractSerializer(typeof(Employee));
ser.WriteObject(writer, p1);
Console.WriteLine("Completed writing Object");
}
catch (SerializationException se)
{
Console.WriteLine("Exception : " + se.Message);
Console.WriteLine(se.Data);
}
finally
{
writer.Close();
fs.Close();
}
// Read the Object from Employee.xml
fs = null;
ser = null;
XmlDictionaryReader reader = null;
try
{
fs = new FileStream("Employee.xml", FileMode.OpenOrCreate);
reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
ser = new DataContractSerializer(typeof(Employee));
Employee newPerson = (Employee)ser.ReadObject(reader);
Console.WriteLine("Reading Employee object:" + newPerson.Name + " "+ newPerson.Age);
}
catch (SerializationException se)
{
Console.WriteLine("Exception : " + se.Message);
Console.WriteLine(se.Data);
}
finally
{
reader.Close();
fs.Close();
}
}
}

NetDataContractSerializer

NetDataContractSerializer includes CLR type information along with serialization. So it might degrade performance. It should be applied only when both serializing and deserializing ends share the same CLR types. DataContractSerializer only writes those which needed to be serialized. This class cannot be inherited. So NetDataContractSerializer will be tightly coupled between the client and server.

Security and Serialization

The user can read or write values using serialization. So serialization requires special permission for updating object values. The SecurityPermission class is used with the SecurityPermissionFlag enumeration flag for controlling access for serialized objects. An internet downloaded file doesn't have permission for updating an the object by default permission. If the class has sensitive information, it should be marked as NonSerialized. Otherwise, data is readable by anone who has permission for reading the code through serialization. The user can't see the values using binary format. But, SOAP or XML format serialization files are readable.

Conclusion

If the server and client application are .NET applications, the user can make use of binary serialization. If the client and server use two different types of systems, then the user can make use of XML type serialization. XML serialization is useful when user wants full control of how the property can be serialized. It supports XSD standard. XML serialization is supported only when a property is public. To serialize only properties, Microsoft recommends making use of DataContractSerializer. But XML serialization is useful when user wants control of the XML structure.

DataContractSerializer serializes properties and fields. It also serializes and deserializes private members. It is faster than XmlSerializer. It doesn't control serialization and serialization of properties. If the user wants more control, use XML serialization instead of DataContractSerializer. .NET even supports interfaces and base classes to build their own serialization format.

History

  • 16 July, 2012: Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

R.selvam
Software Developer (Senior)
India India
Selvam has worked on several technologies like Core Java, VC++, MFC, Windows API and Weblogic server. He takes a lot of interest in reading technical articles and enjoy writing them too. He has been awarded as a Microsoft Community Star in 2004, MVP in 2005-06, SCJP 5.0 in 2009, Microsoft Community Contributor(MCC) 2011.
 
Github : https://github.com/selvamselvam
Web site: http://www15.brinkster.com/selvamselvam
Follow on   LinkedIn

Comments and Discussions

 
QuestionRegarding Serialization PinmemberTridip Bhattacharjee16-Dec-13 2:37 
GeneralMy vote of 3 Pinmemberstolbovoy23-Jul-12 7:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 16 Jul 2012
Article Copyright 2012 by R.selvam
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid