Introduction
You have one of the following problems:
- You need to persist an object to a storage medium.
- You are using RPC.
- You need to stream to a socket.
The Solution
Serialization allows you to convert a graph of objects into a linear sequence of bytes, XML, or SOAP. Once an object is flattened, you can store it or send it over the wire. Serialized data can then be deserialized. Deserialization essentially reconstitutes the graph of objects you initially serialized. Serialization sounds complicated, but in practice, it’s pretty easy because the .NET framework takes care of most of the complexity for you.
Microsoft's .NET framework provides two different options for persisting data or sending it over the network: shallow and deep serialization. Shallow serialization allows for the serialization of read-write property values of an object. Private
data members and objects referenced by the object being serialized are ignored. Shallow serialization is used by Web Services and the XmlSerializer
.
As you may have guessed from the title of this article, the focus of this code sample is on deep serialization. Deep serialization serializes the whole object and any objects referenced by the object being serialized. This code sample demonstrates how to serialize data using the BinaryFormatter
and the SoapFormatter
. Both of these classes perform deep serialization.
In order to be eligible for serialization, an object must be decorated with the [Serializable]
attribute or implement the ISerializable
interface. In the event that performance is an issue, you can opt to exclude a field in an object from serialization by decorating the field with the [NonSerialized]
attribute—this is called selective serialization.
I've written the following code samples to demonstrate how easy it is to implement serialization in your project.
Step 1: Binary Serialization to a Byte Array
Binary serialization uses the BinaryFormatter
which is contained in the System.Runtime.Serialization.Formatters.Binary
namespace
. The BinaryFormatter
classes implement the IRemotingFormatter
interface to support remote procedure calls (RPCs), and the IFormatter
interface (inherited by the IRemotingFormatter
) to support serialization of a graph of objects.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CoreWebLibrary.Utility
{
public static class BinarySerialization
{
public static byte[] BinarySerialize(Object obj)
{
byte[] serializedObject;
MemoryStream ms = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(ms, obj);
ms.Seek(0, 0);
serializedObject = ms.ToArray();
ms.Close();
return serializedObject;
}
public static T BinaryDeSerialize<T>(byte[] serializedObject)
{
MemoryStream ms = new MemoryStream();
ms.Write(serializedObject, 0, serializedObject.Length);
ms.Seek(0, 0);
BinaryFormatter b = new BinaryFormatter();
Object obj = b.Deserialize(ms);
ms.Close();
return (T)obj;
}
}
}
Step 2: Binary Serialization to a File
An example of binary serialization to a file:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CoreWebLibrary.Utility
{
public static class FileSerialization
{
public static void FileSerialize(Object obj, string filePath)
{
FileStream fileStream = null;
try
{
fileStream = new FileStream(filePath, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(fileStream, obj);
}
catch
{
throw;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
}
public static T FileDeSerialize<T>(string filePath)
{
FileStream fileStream = null;
Object obj;
try
{
if (File.Exists(filePath) == false)
throw new FileNotFoundException("The file" +
" was not found.", filePath);
fileStream = new FileStream(filePath, FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
obj = b.Deserialize(fileStream);
}
catch
{
throw;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
return (T)obj;
}
}
}
Step 3: SOAP Serialization to a String
SOAP serialization uses the SoapFormatter
which is contained in the System.Runtime.Serialization.Formatters.Soap
namespace
. SOAP serialization is more versatile than binary serialization, but versatility comes at a significant cost in terms of performance.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;
namespace CoreWebLibrary.Utility
{
public class SoapSerialization
{
public static string SoapMemoryStreamSerialization(object obj,
Encoding encodingType)
{
string xmlResult;
using (Stream stream = new MemoryStream())
{
try
{
SoapFormatter sf = new SoapFormatter();
sf.Serialize(stream, obj);
}
catch
{
throw;
}
stream.Position = 0;
byte[] b = new byte[stream.Length];
stream.Read(b, 0, (int)stream.Length);
xmlResult = encodingType.GetString(b, 0, b.Length);
}
return xmlResult;
}
public T SoapDeserailization<T>(string input,
System.Text.Encoding encodingType)
{
Object obj = null;
using (StringReader sr = new StringReader(input))
{
byte[] b;
b = encodingType.GetBytes(input);
Stream stream = new MemoryStream(b);
try
{
SoapFormatter sf = new SoapFormatter();
obj = (object)sf.Deserialize(stream);
}
catch
{
throw;
}
}
return (T)obj;
}
}
}
Conclusion
Having an understanding of how serialization works is critically important if you want to be effective as a developer. Hopefully, this example has demonstrated that deep serialization is both easy to implement and powerful.
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.