11 October 2007

1. Serialization - BinaryFormatter

Serialization is a process which stores an object as linear sequence of bytes. Deserialization is an opposite process which converts those bytes into the object. Those methods let us simply save object into a stream and then i.e. move it to another computer through the network.
The first way to serialize objects is using the BinaryFormatter. This formatter is the most efficient solution. Below I demonstrate how to use with Person type.
First definition of Business object:

[Serializable]

public class Person : IDeserializationCallback

{

#region Fields

private string _name;

private string _surname;

private int _age;

[NonSerialized]

private int _totalDays;

#endregion


#region Properties

public string Name

{

get { return this._name; }

}

public string Surname

{

get { return this._surname; }

}

public int Age

{

get { return this._age; }

}

public int TotalDays

{

get { return this._totalDays; }

}

#endregion


#region Constructors

public Person(string name, string surname, int age)

{

this._name = name;

this._surname = surname;

this._age = age;

}

#endregion


#region Methods

public void UpdateTotalDays()

{

this._totalDays = this._age * 365;

}

#endregion


#region IDeserializationCallback Members

public void OnDeserialization(object sender)

{

this.UpdateTotalDays();

}

#endregion

}


As you can see this type implements IDeserializationCallback interface. This interface contains only one method OnDeserialization, which is invoked when object is deserializing. So as a content of this method, we can put any initializing methods i.e. the Person type has a TotalDays property but this value in not serialized. That means if we serialize object and then deserialize it we will not able to see old value of TotalDays. Normally this property is counted by launching UpdateTotalDays method. So by taking advantage of IDeserializationCallback we can point that method to be execute while deserializing.
Second step is a static Serializer type:

public static class Serializer

{

#region Fields

public static readonly string SerializePath = @"c:\object.data";

#endregion

#region Methods

public static void Serialize(object graph)

{

FileStream serializationStream = new FileStream(Serializer.SerializePath, FileMode.OpenOrCreate);

BinaryFormatter bf = new BinaryFormatter();

bf.Serialize(serializationStream, graph);

serializationStream.Close();

}

public static object Deserialize()

{

FileStream serializationStream = new FileStream(Serializer.SerializePath, FileMode.Open);

BinaryFormatter bf = new BinaryFormatter();

object graph = bf.Deserialize(serializationStream);

serializationStream.Close();

return graph;

}

#endregion

}

This type is responsible for saving to and loading from object.data file into the Person type. Below I pasted the NUnit test which shows how the Serializer type works.

[Test]

public void SerializeAndDeserializeTest()

{

Person p = new Person("Jarek", "Jurczyk", 26);

p.UpdateTotalDays();

Assert.AreEqual("Jarek", p.Name);

Assert.AreEqual("Jurczyk", p.Surname);

Assert.AreEqual(26, p.Age);

Assert.AreEqual(9490, p.TotalDays);

Serializer.Serialize(p);

FileInfo fi = new FileInfo(Serializer.SerializePath);

Assert.AreEqual(true, fi.Exists);

p = null;

Assert.IsNull(p);

p = Serializer.Deserialize()as Person;

Assert.AreEqual("Jarek", p.Name);

Assert.AreEqual("Jurczyk", p.Surname);

Assert.AreEqual(26, p.Age);

Assert.AreEqual(9490, p.TotalDays);

}


More information:
  • If you don't want to serialize field set the attribute [NonSerialized] (you can apply on private fields)
  • Never change the name of field or class if the object is already serialized
  • Never remove serialized fields
  • If class has already been serialized add the new field but use the [OptionalField]
  • Don't apply the [NonSerialized] for fields which have been already serialized in previous version


In the next post I will describe the SoapFormatter

Labels: , ,

03 October 2007

Unit testes and events

While my last project I met a problem with applying unit testes to asynchronous methods. My program had to load a big amount of data from database. The simple method DownloadData took too much time so I had decided to build and invoke asynchronous method like BeginDownloading. As the data was downloaded the OnDownloaded event was raised. The class had look similarly to this one below.

public class DatabaseFacade

{

public event EventHandler OnDownloaded;

public DatabaseFacade() { }

public virtual void BeginDownloading()

{

Console.WriteLine("Begin downloading");

System.Threading.Thread.Sleep(2000);

this.RaiseOnDownloaded();

}

protected virtual void RaiseOnDownloaded()

{

if (this.OnDownloaded != null)

this.OnDownloaded(this, new EventArgs());

}

}



Now it is the main problem how to test the type of DatabaseFacade with unit tests. It is not really easy because of the sequence invoking each test method. To solve this problem we have to apply the ManualResetEvent. The base task of this class is block the executing the method till the me object call Set which means that all waiting threads can proceed. If the method Set will not called in i.e. 5 seconds then the testing method will stop waiting for the call from ManualResetEvent and carry on executing. Below I attache an example:

[Test]

public void BeginDownloadingTest()

{

ManualResetEvent me = new ManualResetEvent(false);

bool raised = false;

DatabaseFacade df = new DatabaseFacade();

df.OnDownloaded += new EventHandler(delegate(object sender, EventArgs e)

{

raised = true;

Console.WriteLine("Done");

me.Set();

});

df.BeginDownloading();

me.WaitOne(5000, false);

Assert.IsTrue(raised);

}

Labels: , ,