ProFast Computing

Software Development and Consulting Services

Specializing in Microsoft .NET and SQL Application Development

 

Building Serialization into Classes

Introduction

On a recent project I was working on, there was a requirement to save and load the state of various objects used by a database application. The solution was to add serialization functionality to the classes containing the application data.

The initial solution was to build a Visual Studio item template that could be used to quickly create classes that contained built-in capabilities of reading and writing the class property values via XML formatted files or strings. 

A second solution was to build a generic class that takes any class type as a parameter and provides the same read/write XML functionality.

Both solutions provide serialization to files, strings and database tables. Methods that encrypt the serialized values are included for each type of serialization.

Class Template for Visual Studio

 The .NET XML serialization namespace was used to provide the XML serialize/de-serialize functionality.

The System.Reflection namespace was used to provide methods that output the contents of the objects to non-XML formatted string values.

The attached source code does not include any binary or SOAP serialization functionality.

See the following link for the steps needed to add a custom project item template to the Add New Item dialog box:

https://msdn.microsoft.com/en-us/library/tsyyf0yh(v=vs.100).aspx

Selected Save and Load methods from the template source code:

public class ClassTemplateWithSerializers
{
.....

/// <summary>
/// Saves the column definitions contained in the current instance to the specified file. Serialization is used for the save.
/// </summary>
/// <param name="filePath">Full path for output file.</param>

public void SaveToXmlFile(string filePath)
{
XmlSerializer ser = new XmlSerializer(typeof(ClassTemplateWithSerializers));
TextWriter tex = new StreamWriter(filePath);
ser.Serialize(tex, this);
tex.Close();
}

/// <summary>
/// Creates and initializes an instance of the class by loading a serialized version of the instance from a file.
/// </summary>
/// <param name="filePath">Full path for the input file.</param>
/// <returns>An instance of ClassTemplateWithSerializers.</returns>
public static ClassTemplateWithSerializers LoadFromXmlFile(string filePath)
{
XmlSerializer deserializer = new XmlSerializer(typeof(ClassTemplateWithSerializers));
TextReader textReader = new StreamReader(filePath);
ClassTemplateWithSerializers columnDefinitions;
columnDefinitions = (ClassTemplateWithSerializers)deserializer.Deserialize(textReader);
textReader.Close();
return columnDefinitions;
}

Examples that use the template derived code:

private static ClassWithSerializers _classWithSerializers = new ClassWithSerializers();
....
classWithSerializers.IntValue = 25321;
....
// Save class instance
_classWithSerializers.SaveToXmlFile(outputPath);
…..
//Retrieve saved instance into a new instance
ClassWithSerializers newObject = new ClassWithSerializers();
newObject = ClassWithSerializers.LoadFromXmlFile(outputPath);
....

Class Manager Using Generics

If you do not wish to repeat the serialization logic in each class, you can use the ClassManager module. This module uses generics to accept an instance of a class type as a parameter to the constructor. Its methods then operate generically on the class instance.

Selected Save and Load methods from the generic ClassManager:

public class ClassManager<T>
{
.....
/// <summary>
/// Saves the column definitions contained in the current instance to the specified file. Serialization is used for the save.
/// </summary>
/// <param name="filePath">Full path for output file.</param>
public void SaveToXmlFile(string filePath)
{
       XmlSerializer ser = new XmlSerializer(typeof(T));
       TextWriter tex = new StreamWriter(filePath);
       ser.Serialize(tex, _classInstance);
       tex.Close();
}
/// <summary>
/// Creates and initializes an instance of the class by loading a serialized version of the instance from a file.
/// </summary>
/// <param name="filePath">Full path for the input file.</param>
/// <returns>An instance of the object.</returns>
public static T LoadFromXmlFile(string filePath)
{
       XmlSerializer deserializer = new XmlSerializer(typeof(T));
       TextReader textReader = new StreamReader(filePath);
       T columnDefinitions;
       columnDefinitions = (T)deserializer.Deserialize(textReader);
       textReader.Close();
       return columnDefinitions;
}

Examples that use the generic code module:

private static ClassManager<TestClassNoSerializers> _classManager;
.....
//Save object to an XML file
_classManager.SaveToXmlFile(outputPath);
 ....
//Load object from instance saved in XML file
_classManager.SaveToXmlFile(outputPath);
newObject2 = ClassManager<TestClassNoSerializers>.LoadFromXmlFile(outputPath);
ClassManager<TestClassNoSerializers> clsmgr2 = new ClassManager<TestClassNoSerializers>(newObject2);
outputString = clsmgr2.ToXmlString();
.....

Encryption and Database Options

Where security is required, serialization methods that use AES encryption were included in both the class template and generic class manager.

Saving to a database was coded by building methods that use the System.Data.Odbc functionality provided by .NET. In a real-world scenario, you could modify this code to use another .NET database provider.

See the sample code supplied with this article for examples on using encryption and databases with the class serializers.

Points of Interest

Only XML serialization is used for this code. This approach was taken to help calling applications troubleshoot any issues with the serialized object data.

Download Sample Code

Sample code for Building Serialization into Classes