To explain what is required to implement ISerializable for performing custom serialization.
Lead-in
This module has so far discussed the default serialization process. However, you may also want to customize the way data from a given object is serialized.
!Customize Serialization by Implementing ISerializable:
"When some of the data is not valid after deserialization
"When some of the data must be obtained by calculation
!ISerializable Requires:
"GetObjectData method, called during serialization, which returns a PropertyBag of type SerializationInfo
"PropertyBag, which contains the type of the object being serialized and the name/object pairs for the values being serialized
"A constructor, called during deserialization, which uses SerializationInfo to reconstitute the state of the object
*****************************ILLEGAL FOR NON-TRAINER USE******************************
This module has so far discussed the default serialization process. However, you may also want to customize the way that data from a given object is serialized.
Custom serialization can be useful when some of the data that is associated with an object is no longer valid after deserialization. You may want to use custom serialization when working with pointers or hashcodes, or when you want to create data through calculations or other means that allow you to reconstruct the full state of the object during deserialization.
To perform custom serialization, you should implement the ISerializable interface on the given object.
Implementation Details Required by ISerializable
To implement the ISerializable interface, you implement the GetObjectData method on your object and add a constructor that takes a SerializationInfo and a StreamingContext, as shown in Custom Serialization Example in this module.
When GetObjectData is called during serialization, you are responsible for populating a SerializationInfo object. A SerializationInfo object is a
PropertyBag that contains the type of the object that is being serialized and the name/object pairs for the values that are being serialized.
The Formatter emits the data out onto the wire in the method required by its particular format. You are free to serialize as few or as many fields as you want, but the data that is transmitted must be sufficient to reconstitute the entire state of the object. If the base object of the current class implements ISerializable, it is usually correct to call the base object’s ISerializable.GetObjectData and add any additional fields that are required for serializing the derived class to the returned SerializationInfo.
Module 12: Serialization
13
Deserialization
Deserialization occurs during the call to the class’s constructor. If you need to create custom deserialization of an object, you use the object’s SerializationInfo, which has been populated with the type of the object and the name/object pairs that were transmitted over the stream. You are responsible for completely reconstituting the state of the object from this information. If the base class also implements ISerializable, you are responsible for calling the base class’s constructor. The serialization infrastructure will delay the call on this constructor until the entire SerializationInfo has been completed.
If, for example, the SerializationInfo that is transmitted references objects A, B, and C, the SerializationInfo that is passed to the constructor will have been populated with references to objects A, B, and C. However, there is no guarantee that any of the objects that are referenced by A, B, or C has been completed.
Because there is no guarantee that any of the objects that are referenced by A, B, or C have been completed, you cannot safely call any code on A, B, or C that may require the objects to which they refer. For some objects, this code may include code as simple as GetHashCode.
If your code requires you to perform any execution that is based on the value of data that is contained in the objects that are referenced, it is usually best to cache the SerializationInfo and then implement IDeserializationCallback.
14
Module 12: Serialization
Custom Serialization Example
Topic Objective
To provide an example of custom serialization.
Lead-in
This example shows how to provide custom serialization for a class named
ISerializableExample.
[Serializable] public class ExampleFoo : ISerializable [Serializable] public class ExampleFoo : ISerializable
{{ public int i, j, k; public int i, j, k; public ExampleFoo() {} public ExampleFoo() {}
//Then you can read it back in with code like this: IFormatter objFormatterFromStream = new SoapFormatter(); Stream fromStream = new FileStream("myFoo.xml",
Type t = this.GetType(); si.AddValue("TypeObj", t);
}
}
Outputs:
ToFile
i:1
j:20
k:50 FromFile
i:1
j:20
k:50
Module 12: Serialization
17
Security Issues
Topic Objective
To alert students to the need for security when serializing objects.
Lead-in
The serialization engine handles both the public and private state of the objects that are passed to it.
!Serialization Handles an Object’s Private Data
"If private data is sensitive, consider encrypting the stream before transmitting or saving to a disk
"System.Security.Cryptography namespace contains classes to perform cryptography
The CryptoStream class can be used to encrypt streams of serialized data
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The serialization engine handles both the public and private state of the objects that are passed to it. When serializing an object to a stream, you must remember that the stream now contains the public and private data of the object.
If the private data is sensitive, you should treat the stream with particular care. For example, the stream should not be transmitted over the wire or persisted to disk without some form of encryption.
18
Module 12: Serialization
Lab 12: Serialization
Topic Objective
To introduce the lab.
Lead-in
In this lab, you will write a client/server application that uses serialization.
*****************************ILLEGAL FOR NON-TRAINER USE******************************
Objectives
After completing this lab, you will be able to:
•Create an application that uses serialization as it is implemented by the
.NET Framework, to persist an object graph to and from a disk file in both binary and SOAP XML format.
Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab12\Starter, and the solution files are in the folder <install folder>\Labs\Lab12\Solution.
Scenario
In this lab, you will create a Microsoft Visual Studio® .NET console application that uses the common language runtime’s ability to serialize an object graph in memory to disk. You will create binary and SOAP formatter implementations of the application.
In the first exercise, you will create a singly-linked linked list, which you will fill with values and serialize to a file on disk. You will then deserialize the list from the file on disk, thus restoring the list to an object graph in memory.
During deserialization, the elements within the list are swapped multiple times.
In the second exercise, you will modify the application to demonstrate the ability of the .NET Framework’s serialization mechanism to handle object graphs that contain multiple references to the same object and that contain objects that have mutual references, which can create cycles in the graph.
Estimated time to complete this lab: 45 minutes
Module 12: Serialization
19
Exercise 1
Creating the Basic Serialization Application
In this exercise, you will modify the Serialization application to provide methods to serialize and deserialize a linked list.
! To create the basic Serialization application in binary format
1.In the <install folder>\Labs\Lab12\Starter directory, open the Serialization project in Visual Studio .NET and examine the Serialize.cs and LinkedList.cs source files.
2.In Serialize.cs, locate the SaveListToDisk method, and add code to:
a.Create a Stream object that is initialized to a file named Linkedlist.bin by using the static File.Create method.
b.Create a new BinaryFormatter object.
c.Invoke the method of the BinaryFormatter that serializes the LinkedList parameter to the stream.
d.Close the file.
3.In Serialize.cs, locate the LoadListFromDisk method and add code to:
a.Create a Stream object that is initialized to a file named Linkedlist.bin by using the static File.OpenRead method.
b.Create a new BinaryFormatter object.
c.Invoke the method of the BinaryFormatter that deserializes the stream into a LinkedList named list2.
d.Close the file.
e.Output the contents of list2 to console by calling the LinkedList method
Draw().
f.Return list2.
4.Build the Serialization application.
20Module 12: Serialization
5.Step through the application in the Visual Studio .NET debugger, and note that due to the random swapping your output may vary slightly from the following: