Introduction
In Part I of this series, we took a brief look at how to perform binary serialization to persist the state of objects in our application to some form of permanent storage medium and then retrieve them again at a later point in time
In this article we are going to take a quick look at SOAP serialization. This article is going to be quite brief as I don't intend going into a massive amount of detail, mainly because SOAP serialization is now generally considered to be superseded by XML serialization, which we will look at in Part III.
Upgrading the Farmyard
Continuing with the sample farmyard application we looked at in Part I, how do we go about the process of upgrading our software to support saving in SOAP format, as well as binary? Well, as I hinted at in Part I, SOAP serialization uses the same mechanism as binary serialization.
Therefore, as all the relevant classes have already been decorated with the appropriate attributes to support serialization, all that should be required is to substitute the BinaryFormatter
object for a SoapFormatter
object when saving the data:
// C#
public enum FileFormat { Binary = 1, Soap = 2 }
using (Stream fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))
{
IFormatter formatter;
switch ((FileFormat)saveFarmyardDialog.FilterIndex)
{
case FileFormat.Binary: formatter = new BinaryFormatter(); break;
case FileFormat.Soap: formatter = new SoapFormatter(); break;
default: formatter = new BinaryFormatter(); break;
}
formatter.Serialize(fileStream, this.farmyard);
}
' Visual Basic
Public Enum FileFormat
Binary = 1
Soap = 2
End Enum
Using fileStream As Stream = New FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None)
Dim formatter As IFormatter
Select Case DirectCast(saveFarmyardDialog.FilterIndex, FileFormat)
Case FileFormat.Binary
formatter = New BinaryFormatter()
Case FileFormat.Soap
formatter = New SoapFormatter()
Case Else
formatter = New BinaryFormatter()
End Select
formatter.Serialize(fileStream, farmyard)
End Using
...and for loading the data:
// C#
using (Stream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
IFormatter formatter;
switch ((FileFormat)loadFarmyardDialog.FilterIndex)
{
case FileFormat.Binary: formatter = new BinaryFormatter(); break;
case FileFormat.Soap: formatter = new SoapFormatter(); break;
default: formatter = new BinaryFormatter(); break;
}
farmyard = (Farmyard)formatter.Deserialize(fileStream);
}
' Visual Basic
Using FileStream As Stream = New FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)
Dim formatter As IFormatter
Select Case DirectCast(loadFarmyardDialog.FilterIndex, FileFormat)
Case FileFormat.Binary
formatter = New BinaryFormatter()
Case FileFormat.Soap
formatter = New SoapFormatter()
Case Else
formatter = New BinaryFormatter()
End Select
farmyard = DirectCast(formatter.Deserialize(FileStream), Farmyard)
End Using
As you can see, we use a simple switch...case
statement, based on the selected file format from the load/save dialog, to determine whether to instantiate a BinaryFormatter
or a SoapFormatter
object. As before, we are serializing our objects to disk; however if we were using SOAP serialization in a real-world application, we would more likely be serializing to a NetworkStream
.
And that it is it, that should be all that is needed to for our application to work. Well, actually no. Try and run the application as it is, and you will get a dirty great exception when you try to serialize using the SoapFormatter
. The reason? Apparently the SoapFormatter
does not support the serialization of generics, and is therefore throwing its toys out of the pram when it encounters our List<Animal>
object which we have used to underpin our farmyard.
As a (not too elegant) workaround, I have used the following code to shuttle the data to and from a non-generic collection when serializing and de-serializing:
// C#
[NonSerialized]
private List<Animal> animals;
private ArrayList animalsForSerialization;
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
animalsForSerialization = new ArrayList();
foreach (Animal animal in animals)
animalsForSerialization.Add(animal);
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
NewDay();
animals = new List<Animal>();
foreach (Animal animal in animalsForSerialization)
animals.Add(animal);
animalsForSerialization = null;
}
' Visual Basic
<NonSerialized()>
Private animals As List(Of Animal)
Private animalsForSerialization As ArrayList
<OnSerializing()>
Private Sub OnSerializing(ByVal context As StreamingContext)
animalsForSerialization = New ArrayList
For Each animal As Animal In animals
animalsForSerialization.Add(animal)
Next
End Sub
<OnDeserialized()>
Private Sub OnDeserialized(ByVal context As StreamingContext)
NewDay()
For Each animal As Animal In animalsForSerialization
animals.Add(animal)
Next
animalsForSerialization = Nothing
End Sub
Note the use of the OnSerializing
and OnDeserialized
attributes we discussed in Part I to control the serialization process. Also, as a result of our change, we won't be able to load any farmyards which were saved with the previous version of the application. A more elegant solution would, of course, allow for backward compatibility
Summary
SOAP serialization uses the same mechanism as binary serialization; however one major limitation is the inability to serialize generics.
The source code for the farmyard application can be downloaded here.
Next: XML Serialization
Great!This article is creative,there are a lot of new idea,it gives me inspiration.I think I will also inspired by you and think about more new ideas.
ReplyDelete----------------------------------------------------------
New Style Wedding Dresses
Column Wedding Dresses
Wedding Dresses with Sleeves
New Style Flower Girl Dresses
Your article is very smooth, very lively written, using the grammar very well, giving us a lot of fun .. Keep it up! lyj
ReplyDelete