The ExpandoObject offers an easy and efficient way to create data classes. You have seen this data class concept in a previous article.
Sometimes the values of these data classes should be stored in a file to reload them on the next start of the application. Therefore we need an easy way to serialize an ExpandoObject. I have implemented such a CSV and XML serialization within my DynamicObjects github project.
https://github.com/oliverfunke/DynamicObjects/tree/2013-04-13_v1.1.0
With the serialization functions of the implemented ExpandoObjectSerializer you may store flat ExpandoObjects in a CSV or XML file and you may create flat ExpandoObjects from a CSV or XML file. “Flat” means that all properties of the data classes must be standard data types (e.g. int, string, DateTime).
ExpandoObject to CSV
The following source code shows a unit test function. Within this unit test an ExpandoObject will be written to a CSV file and a new ExpandoObject will be created by reading the file.
dynamic element; string csvExport; string fileName = _assemblyDirectory + @"\CsvTest.txt"; //define elements List<IDynamicTableColumn> elementDefinitions = new List<IDynamicTableColumn>() { new DynamicTableColumn<string>("FirstName"), new DynamicTableColumn<string>("LastName"), new DynamicTableColumn<int>("Age"), new DynamicTableColumn<DateTime>("TimeStamp") }; //set values element = new ExpandoObject(); element.FirstName = "Hans"; element.LastName = "Mueller"; element.Age = 30; element.TimeStamp = new DateTime(2012, 12, 24, 1, 2, 3); //export csvExport = ExpandoObjectSerializer.AsCsv(element, true, ',', true); using (StreamWriter writer = new StreamWriter(fileName)) { writer.Write(csvExport); } //import using (StreamReader reader = new StreamReader(fileName)) { element = ExpandoObjectSerializer.FromCsv(ReadFile(reader), elementDefinitions, true, ',', true); } //compare IDictionary<string, object> elementDictionary = element; Assert.AreEqual(4, elementDictionary.Count); Assert.AreEqual("Hans", element.FirstName); Assert.AreEqual("Mueller", element.LastName); Assert.AreEqual(30, element.Age); Assert.AreEqual(2012, element.TimeStamp.Year); Assert.AreEqual(12, element.TimeStamp.Month); Assert.AreEqual(24, element.TimeStamp.Day); Assert.AreEqual(1, element.TimeStamp.Hour); Assert.AreEqual(2, element.TimeStamp.Minute); Assert.AreEqual(3, element.TimeStamp.Second);
To read a file the following function is used.
private static IEnumerable<string> ReadFile(StreamReader reader) { while (reader.EndOfStream == false) { yield return reader.ReadLine(); } }
To import a CSV file the expected file content must be known. Therefore the element definitions must be set. These element definitions containing the names and types of the properties to create. On import of the CSV file the content will be compared with the element definitions.
ExpandoObject to XML
The import and export of an XML file will be done in nearly the same way like the CSV import and export. The following source code shows the according unit test.
dynamic element; string xmlExport; string fileName = _assemblyDirectory + @"\XmlTest.xml"; //define elements List<IDynamicTableColumn> elementDefinitions = new List<IDynamicTableColumn>() { new DynamicTableColumn<string>("FirstName"), new DynamicTableColumn<string>("LastName"), new DynamicTableColumn<int>("Age"), new DynamicTableColumn<DateTime>("TimeStamp") }; //set values element = new ExpandoObject(); element.FirstName = "Hans"; element.LastName = "Mueller"; element.Age = 30; element.TimeStamp = new DateTime(2012, 12, 24, 1, 2, 3); //export xmlExport = ExpandoObjectSerializer.AsXml(element); using (StreamWriter writer = new StreamWriter(fileName)) { writer.Write(xmlExport); } //import using (StreamReader reader = new StreamReader(fileName)) { element = ExpandoObjectSerializer.FromXml(ReadFile(reader), elementDefinitions); } //compare IDictionary<string, object> elementDictionary = element; Assert.AreEqual(4, elementDictionary.Count); Assert.AreEqual("Hans", element.FirstName); Assert.AreEqual("Mueller", element.LastName); Assert.AreEqual(30, element.Age); Assert.AreEqual(2012, element.TimeStamp.Year); Assert.AreEqual(12, element.TimeStamp.Month); Assert.AreEqual(24, element.TimeStamp.Day); Assert.AreEqual(1, element.TimeStamp.Hour); Assert.AreEqual(2, element.TimeStamp.Minute); Assert.AreEqual(3, element.TimeStamp.Second);
Summary
The ExpandoObjectSerializer offers an easy way for the serialization of a flat ExpandoObject.