Recipe 3.33 Choosing a Serializer

Problem

The FCL contains several classes to allow objects to be serialized into different formats. Choosing the correct format for your task and remembering how to use that format can become a chore, especially when there is a mixture of different formats and all of them are on disk. You need some way of simplifying the serialization interfaces to make serialization easy without worrying about the underlying differences in the serialization classes. This will also allow other developers on your team to become proficient with the use of the various serializers more quickly.

Solution

Use the fa §ade design pattern to create the following Serializer class:

 using System; using System.Collections; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Xml.Serialization;  using System.Runtime.Serialization.Formatters.Soap; // Note that you must also add a reference to the following assembly: //  System.Runtime.Serialization.Formatters.Soap.dll [Serializable] public class Serializer {     public Serializer( ) {}     protected Hashtable serializationMap = new Hashtable( );     protected Hashtable serializationTypeOfMap = new Hashtable( );     // Serialize an object     public void SerializeObj(object obj, string destination)     {         SerializeObj(obj, destination, SerializationAction.Default);     }     public void SerializeObj(       object obj, string destination, SerializationAction action)     {         if (action == SerializationAction.RetainAssemblyInfo                action == SerializationAction.RetainPrivateMembers              action == SerializationAction.SmallestFootprint                 action == SerializationAction.Default)         {             BinarySerializeObj(obj, destination);             serializationMap.Add(destination.ToUpper( ), DeserializationType.Binary);         }         else if (action == SerializationAction.MakePortable                   action == SerializationAction.AsSOAPMsg)         {             SoapSerializeObj(obj, destination);             serializationMap.Add(destination.ToUpper( ), DeserializationType.SOAP);         }         else  if (action == SerializationAction.AsXML                    action == SerializationAction.SendToXMLWebService)         {             XmlSerializeObj(obj, destination);             serializationMap.Add(destination.ToUpper( ), DeserializationType.XML);             serializationTypeOfMap.Add(destination.ToUpper( ),                obj.GetType( ).FullName);         }     }     private void BinarySerializeObj(object obj, string destination)     {         BinaryFormatter binFormatter = new BinaryFormatter( );         Stream fileStream = new FileStream(destination, FileMode.Create,            FileAccess.Write, FileShare.None);         binFormatter.Serialize(fileStream, obj);         fileStream.Close( );     }     private void SoapSerializeObj(object obj, string destination)     {         SoapFormatter SOAPFormatter = new SoapFormatter( );         Stream fileStream = new FileStream(destination, FileMode.Create,            FileAccess.Write, FileShare.None);         SOAPFormatter.Serialize(fileStream, obj);         fileStream.Close( ); }     private void XmlSerializeObj(object obj, string destination)     {         XmlSerializer XMLFormatter = new XmlSerializer(obj.GetType( ));         Stream fileStream = new FileStream(destination, FileMode.Create,            FileAccess.Write, FileShare.None);         XMLFormatter.Serialize(fileStream, obj);         fileStream.Close( );     }     // DeSerialize an object     public object DeSerializeObj(string source)     {         return (DeSerializeObj(source,                 (DeserializationType)serializationMap[source.ToUpper( )]));     }     public object DeSerializeObj(string source, DeserializationType type)     {         object retObj = null;         if (type == DeserializationType.Binary)         {             retObj = BinaryDeSerializeObj(source);             serializationMap.Remove(source.ToUpper( ));         }         else if (type == DeserializationType.SOAP)         {             retObj = SoapDeSerializeObj(source);             serializationMap.Remove(source.ToUpper( ));         }         else if (type == DeserializationType.XML)         {             retObj = XmlDeSerializeObj(source);             serializationMap.Remove(source.ToUpper( ));             serializationTypeOfMap.Remove(source.ToUpper( ));         }         return (retObj);     }     private object BinaryDeSerializeObj(string source)     {         BinaryFormatter binFormatter = new BinaryFormatter( );         Stream fileStream = new FileStream(source, FileMode.Open, FileAccess.Read,                                            FileShare.None);         object DeserializedObj = binFormatter.Deserialize(fileStream);         fileStream.Close( );         return (DeserializedObj);     }         private object SoapDeSerializeObj(string source)     {         SoapFormatter SOAPFormatter = new SoapFormatter( );         Stream fileStream = new FileStream(source, FileMode.Open, FileAccess.Read,                                            FileShare.None);         object DeserializedObj = SOAPFormatter.Deserialize(fileStream);         fileStream.Close( );         return (DeserializedObj);     }     private object XmlDeSerializeObj(string source)     {         XmlSerializer XMLFormatter = new              XmlSerializer(Type.GetType((string)serializationTypeOfMap                                        [source.ToUpper( )]));         Stream fileStream = new FileStream(source, FileMode.Open,            FileAccess.Read, FileShare.None);         object DeserializedObj = XMLFormatter.Deserialize(fileStream);         fileStream.Close( );         return (DeserializedObj);     } } public enum SerializationAction {     Default = 0,     RetainAssemblyInfo,     RetainPrivateMembers,     MakePortable,     SmallestFootprint,     SendToXMLWebService,     AsSOAPMsg,     AsXML } public enum DeserializationType {     Binary = 0,     SOAP,     XML } 

Discussion

The fa §ade design pattern uses a fa §ade class to provide a simple interface to a group of underlying objects that do similar work. Any client that wants to use one of the underlying objects can go through the fa §ade object. In effect, the fa §ade pattern abstracts away the complexities and disparities between the underlying classes. This allows a uniform, and much easier to use, interface to be presented to the clients that wish to use any of these underlying objects.

The fa §ade object can decide which underlying object will be used to perform the action requested , but it is not required to do so. The user could even pass in one or more arguments allowing the fa §ade object to determine which underlying object to use. The nice thing about this pattern is that if the client decides that they need more flexibility than is provided by the fa §ade object, they can choose to use the underlying objects and contend with their individual complexities. Also, if other serialization classes are created, they can easily be added to the fa §ade object without breaking the existing code.

The class that acts as the fa §ade in this recipe is the Serializer class. This class abstracts away the various interfaces to the various serializers that ship with the FCL, namely:

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
System.Xml.Serialization.XmlSerializer
System.Runtime.Serialization.Formatters.Soap.SoapFormatter

In addition, this class provides an enumeration called SerializationAction , which can be passed to the SerializeObj method for the Serializer to choose the best type of serialization object to use to serialize the input data. The various values of the SerializationAction enumeration and their meanings are:


Default

Uses the default serialization object, which is BinaryFormatter .


RetainAssemblyInfo

Uses the BinaryFormatter . This value is used when the assembly information needs to be retained by the serialization process.


RetainPrivateMembers

Uses the BinaryFormatter . This value is used when private members need to be added to the serialization stream.


SmallestFootprint

Uses the BinaryFormatter . This value is used when the client wants the serialization data in the most compact form possible. As an added benefit, this serialization method is also the fastest .


MakePortable

Uses the SoapFormatter . This value is used when the serialization data needs to be in the most portable form (i.e., SOAP).


AsSOAPMsg

Uses the SoapFormatter . This value tells the fa §ade object to explicitly use the SoapFormatter .


SendToXMLWebService

Uses the XmlSerializer . This value is used when the serialized object will be sent to an ASP.NET XML web service.


AsXML

Uses the XmlSerializer . This value tells the fa §ade object to explicitly use the XmlSerializer .

The interface to the Serializer object contains two sets of overloaded methods : SerializeObj and DeSerializeObj . Both SerializeObj methods accept an object to be serialized in the obj parameter and a location to store the serialized object in the destination parameter. The second SerializeObj method also has a parameter that accepts a SerializationAction enumeration, which was previously discussed. The first SerializeObj method does not have this parameter and so defaults to using the SerializationAction.Default enumeration value.

You need to have permissions to open a FileStream directly from your code in order to use this recipe. This recipe cannot be used in a partial-trust environment where you are obliged to get your FileStream s either from IsolatedStorage or from a FileDialog .


Both DeSerializeObj methods accept a source string indicating where the serialized object is located. The second overloaded DeSerializeObj method also accepts a DeserializationType enumeration. This enumeration contains three values Binary , SOAP , and XML and is used to explicitly inform the underlying Deserialize methods of which serialization objects to use. If the first DeSerializeObj method is called, the values cached in the SerializeObj methods are used to deserialize the object without the client having to remember various small details about the serialization process used to initially serialize the object. If the SerializeObj methods are not used to serialize the object, one of the various DeserializationType enumeration values can be explicitly passed as an argument to inform the DeSerializeObj method which underlying deserialization method to call.

The serializationMap and serializationTypeOfMap Hashtables are used to cache various pieces of information during the serialization process. The SerializeObj methods use the serializationMap Hashtable to map the destination of the serialized object to the type of serialization process used. This allows the DeSerializeObj methods to use the source parameter to locate the pertinent information in the serializationMap Hashtable . The serializationTypeOfMap is used only when the XmlSerializer object is used for serialization. Upon deserialization, the XmlSerializer uses the serializationTypeOfMap to locate the full type name that is to be deserialized.

The following code serializes an integer array to the file TestBinSerXML.txt and then deserializes it into the retArray variable:

 Serializer s = new Serializer( ); s.SerializeObj(new int[10] {1,2,3,4,5,6,7,8,9,10}, @"C:\TestBinSerXML.txt",                 SerializationAction.AsXML); int[] retArray = (int[])s.DeSerializeObj(@"c:\TestBinSerXML.txt"); 

See Also

See the "Serializing Objects," "Introducing XML Serialization," and "Serialization Guidelines" topics in the MSDN documentation.



C# Cookbook
C# 3.0 Cookbook
ISBN: 059651610X
EAN: 2147483647
Year: 2003
Pages: 315

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net