Article

This article is in continuation to this post Serialization in .NET Part 1

Serializable attribute

This attribute is applied to a class. It is used to mark the class as serializable. It indicates to the .NET runtime that the instances of the class can be serialized. By default, objects are not available for serialization. We cannot serialize an object that is not marked as Serializable. If we attempt to serialize an object that is not marked as Serializable, the runtime throws a SerializationException.

NonSerialized attribute

This attribute is applied to a particular member variable of a class. Before you apply this attribute to any member variable, make sure that you mark its class as Serializable. Marking a member variable of a class as NonSerialized prevents it from being serialized. The serializer does not copy that variable into the byte stream. Other member variables, not marked with this attribute, are serialized.

Certain information that you may not want to serialize:

  1. You may want to prevent sending the sensitive data for security reasons like encryption keys, passwords.

  2. The data that is too large to be copied for e.g. an image

  3. The data that might not be valid when an object is deserialized. For example, thread id, file handle, etc. is of no significance in a different process on a different machine. It does not make sense to serialize such transient values.

  4. A member variable may refer to other objects that are not marked with the Serializable attribute. In other words, it references non-serializable objects. A runtime error will occur if you attempt to serialize such a variable. The solution is to mark such variable as NonSerialized. Then the serializer will not attempt to serialize the referenced objects.

Binary Serialization Example

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

//Mark ChatRoom class as Serializable
[Serializable]
class ChatRoom {

    private int roomId;
    private string roomName;

    //We don’t want to serialize the list of 'ever-changing' online users, therefore mark it as  NonSerialized

    [NonSerialized]
    private ArrayList onlineUsers = new ArrayList();

    public ChatRoom(int roomId, string roomName) {
        this.roomId = roomId;
        this.roomName = roomName;
    }
    public void AddUser(string name) {
        onlineUsers.Add(name);
    }
    public void Display() {
        Console.WriteLine("Room Id: {0}", roomId);
        Console.WriteLine("Room Name: {0}", roomName);
    }
}

class BinarySerializeDemo {
    public static void Main() {
        ArrayList rooms = new ArrayList();

        ChatRoom room1 = new ChatRoom(1, "Current Affairs");
        room1.AddUser("John");
        room1.AddUser("Joe");

        ChatRoom room2 = new ChatRoom(2, "Friends Forever");
        room2.AddUser("Steve");

        //Add room1 and room2 in the 'rooms' ArrayList
        rooms.Add(room1);
        rooms.Add(room2);

        //Create the ChatBinary.dat file and link the stream writer with this file
        FileInfo fileRef = new FileInfo("ChatBinary.dat");
        Stream writer = fileRef.Create();

        //Serialize the rooms object using the BinaryFormatter.
        //We do not need to explicitly iterate through the rooms collection
        //to serialize the individual ChatRoom objects. All of its elements are 
        //automatically serialized in sequence as ArrayList class is serializable.
        //Write the serialized data to a target stream writer
        BinaryFormatter binFormat = new BinaryFormatter();
        binFormat.Serialize(writer, rooms);
        writer.Close();

        //Open the ChatBinary.dat file to read from
        Stream reader = fileRef.Open(FileMode.Open, FileAccess.Read, FileShare.None);

        //Since the Deserialize() method's return type is of type Object,
        //we need to downcast it into the appropriate type.
        ArrayList dRooms = (ArrayList) binFormat.Deserialize(reader);
        reader.Close();

        foreach (ChatRoom room in dRooms)
            room.Display();
    }
}

Since the onlineUsers ArrayList variable is marked as NonSerialized, the serializer will ignore it. Neither the onlineUsers ArrayList object nor any of the user name strings will be serialized. When the byte stream is deserialized, the onlineUsers will not be recreated. This implies that the deserialized ChatRoom objects will contain no onlineUsers ArrayList object at all. The onlineUsers member variable will contain a null reference. In this scenario, when you access the AddUser(), make sure that onlineUsers should not be null in order to prevent the runtime errors.

Using the BinaryFormatter deep serialization technique, we’re now able to serialize/deserialize the private member variables roomId and roomName.

Output

Room Id: 1
Room Name: Current Affairs

Room Id: 2
Room Name: Friends Forever

SOAP Serialization Example

Now we'll serialize the ChatRoom object using the SoapFormatter. This allows us to share the data with any application on any platform.

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

class ChatRoom {
    //Same as before
}

class SoapSerializeDemo {
    public static void Main() {

        ...

        //Create ChatSoap.xml file and link the stream writer with this file
        FileInfo fileRef = new FileInfo("ChatSoap.xml");
        Stream writer = fileRef.Create();

        //Serialize rooms object using the SoapFormatter. It serializes objects into
        //SOAP messages. You’ll notice the envelope, the body and application-specific 
        //header tags in ChatSoap.xml file.
        //The generated XML stores the entire object graph.
        SoapFormatter soapFormat = new SoapFormatter();
        soapFormat.Serialize(writer, rooms);
        writer.Close();

        //Open the ChatSoap.xml file to read from
        Stream reader = fileRef.Open(FileMode.Open, FileAccess.Read, FileShare.None);

        //The SOAP message is parsed and the serialized objects are extracted from it.
        //Then the deserialization takes place and the entire object graph is 
        //constructed and all references are reinstated.
        ArrayList dRooms = (ArrayList) soapFormat.Deserialize(reader);
        reader.Close();

        foreach (ChatRoom room in dRooms)
            room.Display();
    }
}

For Part 3, click this link: Serialization in .NET - Part 3