Serialization using different formats in .NET
How to do serialization using different formats in .NET.
- Download basic serialization demo project - 4.58 KB
- Download custom serialization demo project - 4.75 KB
- Download XML serialization demo project - 4.81 KB
- Download SOAP serialization demo project - 4.66 KB
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.
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 DataContractSeri
alizer
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.