[Serializable]
public class BaseEntity
{
public BaseEntity() { }
}
I will add later some extension method that will give further help.
[Serializable]
public class BaseEntityList<TEntity> : List<TEntity>
where TEntity : BaseEntity
{
public Int32 VirtualItemCount;
public BaseEntityList()
{
}
public BaseEntityList(Int32 capacity)
: base(capacity)
{
}
public BaseEntityList(IEnumerable<TEntity> collection)
: base(collection)
{
}
public virtual void FromEntityArray(BaseEntity[] entityArray)
{
Clear();
AddRange((TEntity[])entityArray);
}
public virtual void FromIEnumerable(IEnumerable<TEntity> entityList)
{
Clear();
AddRange((TEntity[])entityList);
}
}
Please note that I added different constructors and some methods that can become useful (but maybe you'll never use them).
[Serializable]
public class record : BaseEntity
{
public record() { }
public record(IDataReader dr)
{
PopulateIndexes(dr);
prefix = dr.GetString(index_prefix);
title = dr.GetString(index_title);
document_id = dr.GetInt32(index_document_id);
revision = dr.GetString(index_revision);
class_id = dr.GetInt32(index_class_id);
name = dr.GetString(index_name);
description = dr.IsDBNull(index_description) ? null : dr.GetString(index_description);
}
public String prefix { get; set; }
public String title { get; set; }
public Int32 document_id { get; set; }
public String revision { get; set; }
public Int32 class_id { get; set; }
public String name { get; set; }
public String description { get; set; }
#region Indexes
private static Int32 index_prefix = -1;
private static Int32 index_title = -1;
private static Int32 index_document_id = -1;
private static Int32 index_revision = -1;
private static Int32 index_class_id = -1;
private static Int32 index_name = -1;
private static Int32 index_description = -1;
private void PopulateIndexes(IDataReader dr)
{
if (index_prefix == -1)
{
index_prefix = dr.GetOrdinal("prefix");
index_title = dr.GetOrdinal("title");
index_document_id = dr.GetOrdinal("document_id");
index_revision = dr.GetOrdinal("revision");
index_class_id = dr.GetOrdinal("class_id");
index_name = dr.GetOrdinal("name");
index_description = dr.GetOrdinal("description");
}
}
#endregion
}
Note that I chose to read all the field indexes and keep them in static variables. This can improve performances when you have many records to read, because the DataReader will point to the column index, rather than reading it each time.
public static void ResetIndexes()
{
index_prefix = -1;
index_title = -1;
index_document_id = -1;
index_revision = -1;
index_class_id = -1;
index_name = -1;
index_description = -1;
}
This method should be public.
[Serializable]
public class records : BaseEntityList<record>
{
public records() { }
public records(IDataReader dr)
{
record.ResetIndexes();
while (dr.Read())
Add(new record(dr));
}
}
This is essentially a List of objects and I put a constructor with a IDataReader (you may pass to it a SqlDataReader or other types of DataReader that inherit from IDataReader).
private String SerializeEntityXML<T>(T Entity)
{
using (MemoryStream ms = new MemoryStream())
{
new System.Xml.Serialization.XmlSerializer(typeof(T)).Serialize(ms, Entity);
ms.Position = 0;
using (StreamReader sr = new StreamReader(ms))
return sr.ReadToEnd();
}
}
private T DeserializeEntityXML<T>(String SerializedEntity)
{
using (MemoryStream memoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(SerializedEntity)))
{
T retValue = default(T);
memoryStream.Position = 0;
retValue = (T)new System.Xml.Serialization.XmlSerializer(typeof(T)).Deserialize(memoryStream);
return retValue;
}
}
private void Test()
{
records r = null;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings["sqlConnectionString"].ConnectionString))
{
conn.Open();
using (System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand()
{
Connection = conn,
CommandText = "select '1234' as prefix,'Document 1' as title,946 as document_id,'1.1' as revision,24 as class_id,'Type 01' as name,null as description union select '1234' as prefix,'Document 2' as title,947 as document_id,'1.1' as revision,24 as class_id,'Type 01' as name,null as description",
CommandType = CommandType.Text
})
{
r = new records(comm.ExecuteReader());
}
}
String serialized = SerializeEntityXML<records>(r);
File.WriteAllText(@"c:\temp\records.xml", serialized, System.Text.Encoding.UTF8);
records r_deserialized = DeserializeEntityXML<records>(File.ReadAllText(@"c:\temp\records.xml", System.Text.Encoding.UTF8));
}
<?xml version="1.0"?>
<ArrayOfRecord xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<record>
<prefix>1234</prefix>
<title>Document 1</title>
<document_id>946</document_id>
<revision>1.1</revision>
<class_id>24</class_id>
<name>Type 01</name>
</record>
<record>
<prefix>1234</prefix>
<title>Document 2</title>
<document_id>947</document_id>
<revision>1.1</revision>
<class_id>24</class_id>
<name>Type 01</name>
</record>
</ArrayOfRecord>
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
private static String CompressToBase64String(String inputString, Encoding encoding, String typeName)
{
#if DEBUG
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
#endif
Byte[] DataToCompress = encoding.GetBytes(inputString);
using (MemoryStream msOut = new MemoryStream())
{
using (DeflaterOutputStream z = new DeflaterOutputStream(msOut))
z.Write(DataToCompress, 0, DataToCompress.Length);
Byte[] byteArr = msOut.ToArray();
#if DEBUG
stopWatch.Stop();
Debug.WriteLine(String.Format("Entity '{0}' compression in {1} milliseconds. Original size: {2} bytes. Compressed size: {3} bytes (ratio: {4}%).", typeName, stopWatch.ElapsedMilliseconds, DataToCompress.Length, byteArr.Length, Math.Round((Decimal)(byteArr.Length * 100 / DataToCompress.Length), 2)));
#endif
return Convert.ToBase64String(byteArr);
}
}
I left 2 conditional-compile sections where you can see in your Output window how much you saved by using compression.
internal static String SerializeEntityXML<T>(T Entity, Boolean Compress)
{
Type t = typeof(T);
try
{
using (MemoryStream ms = new MemoryStream())
{
new System.Xml.Serialization.XmlSerializer(t).Serialize(ms, Entity);
ms.Position = 0;
using (StreamReader sr = new StreamReader(ms))
{
String serializedString = sr.ReadToEnd();
if (Compress)
return CompressToBase64String(serializedString, System.Text.Encoding.UTF8, t.ToString());
else
return serializedString;
}
}
}
catch (Exception ex)
{
throw new Exception("Error during entity serialization.", ex);
}
}
Now you can call the serialization method with the new parameter set as "true".
private static Byte[] DecompressFromBase64String(String SerializedEntity)
{
Byte[] buffer = null;
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(SerializedEntity)))
{
ms.Position = 0;
using (InflaterInputStream z = new InflaterInputStream(ms))
{
using (MemoryStream unzipped = new MemoryStream())
{
Int32 size;
Byte[] b = new Byte[4096];
while ((size = z.Read(b, 0, b.Length)) > 0)
unzipped.Write(b, 0, size);
if (unzipped.Length == 0)
{
Debug.WriteLine(String.Format("Error while decompressing string: '{0}'. Output is empty string.", SerializedEntity));
throw new Exception(String.Format("Error while decompressing string: '{0}'. Output is empty string.", SerializedEntity));
}
unzipped.Position = 0;
buffer = unzipped.GetBuffer();
}
}
}
return buffer;
}
And, as before, you can change the DeserializeXML method:
internal static T DeserializeEntityXML<T>(String SerializedEntity, Boolean IsCompressed)
{
Type t = typeof(T);
if (String.IsNullOrWhiteSpace(SerializedEntity))
{
Debug.WriteLine(String.Format("Error in DeserializeEntity<{0}> -- Input string is empty", t.ToString()));
throw new Exception(String.Format("Error in DeserializeEntity<{0}> -- Input string is empty", t.ToString()));
}
#if DEBUG
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Int64 DecompressionMilliseconds = 0;
#endif
Byte[] buffer = null;
if (IsCompressed)
{
buffer = DecompressFromBase64String(SerializedEntity);
#if DEBUG
DecompressionMilliseconds = stopWatch.ElapsedMilliseconds;
#endif
}
else
buffer = System.Text.Encoding.UTF8.GetBytes(SerializedEntity);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
T retValue = default(T);
memoryStream.Position = 0;
retValue = (T)new System.Xml.Serialization.XmlSerializer(t).Deserialize(memoryStream);
#if DEBUG
stopWatch.Stop();
Debug.WriteLine(String.Format("Entity '{0}' XML deserialization in {1} milliseconds{2}", t.ToString(), stopWatch.ElapsedMilliseconds, IsCompressed ? String.Format(", ({0} of wich were used for decompression).", DecompressionMilliseconds) : "."));
#endif
return retValue;
}
}
And this is the output from the decompression method:
public static class BaseEntity_Extensions
{
public static String Serialize<T>(this T t, Boolean Compress)
{
return BaseEntity_Methods.SerializeEntityXML(t, Compress);
}
public static T Deserialize<T>(this T t, String SerializedEntity, Boolean IsCompressed)
{
return t = BaseEntity_Methods.DeserializeEntityXML<T>(SerializedEntity, IsCompressed);
}
}
Please note that I am pointing to a "BaseEntity_Methods", that is the class where I have put the above serialization/deserializat
String serialized = r.SerializeXML(true);
File.WriteAllText(@"c:\temp\records.xml", serialized, System.Text.Encoding.UTF8);
records r_deserialized = new records().DeserializeXML(File.ReadAllText(@"c:\temp\records.xml", System.Text.Encoding.UTF8), true);
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Test()
{
// BREAKPOINT HERE....
String Connectionstring = textBox1.Text;
records r = null;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
conn.Open();
using (System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand()
{
Connection = conn,
CommandText = "select '1234' as prefix,'Document 1' as title,946 as document_id,'1.1' as revision,24 as class_id,'Type 01' as name,null as description union select '1234' as prefix,'Document 2' as title,947 as document_id,'1.1' as revision,24 as class_id,'Type 01' as name,null as description",
CommandType = CommandType.Text
})
{
r = new records(comm.ExecuteReader());
}
}
String serialized = r.SerializeXML(true);
File.WriteAllText(@"c:\temp\records.xml", serialized, System.Text.Encoding.UTF8);
records r_deserialized = new records().DeserializeXML(File.ReadAllText(@"c:\temp\records.xml", System.Text.Encoding.UTF8), true);
}
private void button1_Click(object sender, EventArgs e)
{
Test();
}
}
#region "Record and Records" Entities
[Serializable]
public class records : BaseEntityList<record>
{
public records() { }
public records(IDataReader dr)
{
record.ResetIndexes();
while (dr.Read())
Add(new record(dr));
}
}
[Serializable]
public class record : BaseEntity
{
public record() { }
public record(IDataReader dr)
{
PopulateIndexes(dr);
prefix = dr.GetString(index_prefix);
title = dr.GetString(index_title);
document_id = dr.GetInt32(index_document_id);
revision = dr.GetString(index_revision);
class_id = dr.GetInt32(index_class_id);
name = dr.GetString(index_name);
description = dr.IsDBNull(index_description) ? null : dr.GetString(index_description);
}
public String prefix { get; set; }
public String title { get; set; }
public Int32 document_id { get; set; }
public String revision { get; set; }
public Int32 class_id { get; set; }
public String name { get; set; }
public String description { get; set; }
#region Indexes
private static Int32 index_prefix = -1;
private static Int32 index_title = -1;
private static Int32 index_document_id = -1;
private static Int32 index_revision = -1;
private static Int32 index_class_id = -1;
private static Int32 index_name = -1;
private static Int32 index_description = -1;
private void PopulateIndexes(IDataReader dr)
{
if (index_prefix == -1)
{
index_prefix = dr.GetOrdinal("prefix");
index_title = dr.GetOrdinal("title");
index_document_id = dr.GetOrdinal("document_id");
index_revision = dr.GetOrdinal("revision");
index_class_id = dr.GetOrdinal("class_id");
index_name = dr.GetOrdinal("name");
index_description = dr.GetOrdinal("description");
}
}
public static void ResetIndexes()
{
index_prefix = -1;
index_title = -1;
index_document_id = -1;
index_revision = -1;
index_class_id = -1;
index_name = -1;
index_description = -1;
}
#endregion
}
#endregion
#region BaseEntity
[Serializable]
public class BaseEntity
{
public BaseEntity() { }
}
public static class BaseEntity_Extensions
{
public static String SerializeXML<T>(this T t, Boolean Compress)
{
return BaseEntity_Methods.SerializeEntityXML(t, Compress);
}
public static T DeserializeXML<T>(this T t, String SerializedEntity, Boolean IsCompressed)
{
return t = BaseEntity_Methods.DeserializeEntityXML<T>(SerializedEntity, IsCompressed);
}
}
#endregion
#region BaseEntityList
[Serializable]
public class BaseEntityList<TEntity> : List<TEntity>
where TEntity : BaseEntity
{
public Int32 VirtualItemCount;
public BaseEntityList()
{
}
public BaseEntityList(Int32 capacity)
: base(capacity)
{
}
public BaseEntityList(IEnumerable<TEntity> collection)
: base(collection)
{
}
public virtual void FromEntityArray(BaseEntity[] entityArray)
{
Clear();
AddRange((TEntity[])entityArray);
}
public virtual void FromIEnumerable(IEnumerable<TEntity> entityList)
{
Clear();
AddRange((TEntity[])entityList);
}
}
#endregion
#region BaseEntity_Methods
internal static class BaseEntity_Methods
{
private static String CompressToBase64String(String inputString, Encoding encoding, String typeName)
{
#if DEBUG
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
#endif
Byte[] DataToCompress = encoding.GetBytes(inputString);
using (MemoryStream msOut = new MemoryStream())
{
using (DeflaterOutputStream z = new DeflaterOutputStream(msOut))
z.Write(DataToCompress, 0, DataToCompress.Length);
Byte[] byteArr = msOut.ToArray();
#if DEBUG
stopWatch.Stop();
Debug.WriteLine(String.Format("Entity '{0}' compression in {1} milliseconds. Original size: {2} bytes. Compressed size: {3} bytes (ratio: {4}%).", typeName, stopWatch.ElapsedMilliseconds, DataToCompress.Length, byteArr.Length, Math.Round((Decimal)(byteArr.Length * 100 / DataToCompress.Length), 2)));
#endif
return Convert.ToBase64String(byteArr);
}
}
private static Byte[] DecompressFromBase64String(String SerializedEntity)
{
Byte[] buffer = null;
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(SerializedEntity)))
{
ms.Position = 0;
using (InflaterInputStream z = new InflaterInputStream(ms))
{
using (MemoryStream unzipped = new MemoryStream())
{
Int32 size;
Byte[] b = new Byte[4096];
while ((size = z.Read(b, 0, b.Length)) > 0)
unzipped.Write(b, 0, size);
if (unzipped.Length == 0)
{
Debug.WriteLine(String.Format("Error while decompressing string: '{0}'. Output is empty string.", SerializedEntity));
throw new Exception(String.Format("Error while decompressing string: '{0}'. Output is empty string.", SerializedEntity));
}
unzipped.Position = 0;
buffer = unzipped.GetBuffer();
}
}
}
return buffer;
}
#region Serialization / Deserialization methods
#region XML serializer/deserializer
internal static String SerializeEntityXML<T>(T Entity, Boolean Compress)
{
Type t = typeof(T);
try
{
#if DEBUG
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
#endif
using (MemoryStream ms = new MemoryStream())
{
new XmlSerializer(t).Serialize(ms, Entity);
// Reposition the stream cusror to the first byte.
ms.Position = 0;
using (StreamReader sr = new StreamReader(ms))
{
String serializedString = sr.ReadToEnd();
#if DEBUG
stopWatch.Stop();
Debug.WriteLine(String.Format("Entity '{0}' XML serialization in {1} milliseconds. Serialized string length: {2}", t.ToString(), stopWatch.ElapsedMilliseconds, serializedString.Length));
#endif
if (Compress)
return BaseEntity_Methods.CompressToBase64String(serializedString, Encoding.UTF8, t.ToString());
else
return serializedString;
}
}
}
catch (Exception ex)
{
throw new Exception("Error during entity serialization.", ex);
}
}
internal static T DeserializeEntityXML<T>(String SerializedEntity, Boolean IsCompressed)
{
Type t = typeof(T);
if (String.IsNullOrWhiteSpace(SerializedEntity))
{
Debug.WriteLine(String.Format("Error in DeserializeEntity<{0}> -- Input string is empty", t.ToString()));
throw new Exception(String.Format("Error in DeserializeEntity<{0}> -- Input string is empty", t.ToString()));
}
#if DEBUG
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Int64 DecompressionMilliseconds = 0;
#endif
Byte[] buffer = null;
if (IsCompressed)
{
buffer = DecompressFromBase64String(SerializedEntity);
#if DEBUG
DecompressionMilliseconds = stopWatch.ElapsedMilliseconds;
#endif
}
else
buffer = Encoding.UTF8.GetBytes(SerializedEntity);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
T retValue = default(T);
memoryStream.Position = 0;
retValue = (T)new XmlSerializer(t).Deserialize(memoryStream);
#if DEBUG
stopWatch.Stop();
Debug.WriteLine(String.Format("Entity '{0}' XML deserialization in {1} milliseconds{2}", t.ToString(), stopWatch.ElapsedMilliseconds, IsCompressed ? String.Format(", ({0} of wich were used for decompression).", DecompressionMilliseconds) : "."));
#endif
return retValue;
}
}
#endregion
#endregion
}
#endregion
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)