BizTalk Utilities CV ,   Jobs ,   Code library  
 
Home Page
XmlSerializer
Surrogate Selectors
ISerializable
Streaming Context States
Custom Serialization
IXmlSerializable
DataSet Object
Namespace at runtime
XmlSerializer Namespaces
Serialization Namespaces
Event notifications
Serializing Objects
any and anyAttribute
XmlAnyElement
Serializing XML nodes
Choice Model Groups
Generic XmlSerializer
Runtime Overrides
Runtime Customization
Customizing Xml Serialization
Advanced XmlSerializer
<< XML DOM
XQuery >>
 

By :Mark Wilson
I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
First posted :03/24/2008
Times viewed :589

 

Serialization Surrogate

For the remainder of this chapter we will develop an example to demonstrate how we can register a serialization surrogate with a formatter. First, we need a class that the surrogate is going to serialize. The class is shown in the following listing (12.3).

22        Listing 12.3: A class without the Serializable attribute.

public sealed class NonSerializable

{

  public NonSerializable ()

  {

    Console.WriteLine( "NonSerializable ctor" );

  }

  private string _privateString;

  public string _publicString = "aPublicString";

}

There is nothing special about this class, actually, it’s pretty useless. Nevertheless it will help us to understand how surrogates work. The best way to serialize this class is through a surrogate because it is not marked with the Serializable attribute and it is also declared sealed, therefore we cannot derive from it to make it serializable. You will come across many sealed classes when you get going with programming on the .NET platform. Knowing how to serialize them, even when they are not marked serializable, is very useful.

ISerializationSurrogate

Next, we are going to write the surrogate. The surrogate class has to implement the ISerializationSurrogate methods: GetObjectData() and SetObjectData() for the formatter to delegate serialization and deserialization to the surrogate.

23        Listing 12.4: A serialization surrogate for the NonSerializable class. The surrogate accesses private data members of the NonSerializable objects through reflection.

using System;

using System.Reflection; // to access private data members

using System.Runtime.Serialization; // for ISerializationSurrogate and

                                    // related classes

// No [Serializable] required

public class NonSerializableSurrogate : ISerializationSurrogate

{

  public void GetObjectData(object obj,

    SerializationInfo info,

    StreamingContext context)

  {

    NonSerializable nsObj = obj as NonSerializable;          |#1

    if( nsObj != null )

    {

      info.AddValue( "PublicMember", nsObj._publicString );

      info.AddValue( "PrivateMember",

        nsObj.GetType().GetField("_privateString",           |#2

          BindingFlags.Instance                              |

            | BindingFlags.NonPublic ).GetValue( nsObj ) );  |

    }

  } // GetObjectData

  public object SetObjectData(object obj,

    SerializationInfo info,

    StreamingContext context,

    ISurrogateSelector selector)

  {

    NonSerializable nsObj = obj as NonSerializable;          |#3

    if( nsObj != null )

    {

      nsObj._publicString = info.GetString( "PublicMember" );

      nsObj.GetType().GetField("_privateString",             |#4

        BindingFlags.Instance                                |

          | BindingFlags.NonPublic ).SetValue(nsObj,         |

            info.GetString( "PrivateMember" ) );             |

    }

    return obj;                                              |#5

  }

}

(annotation) <#1 Safety check that we are really handling the correct object type.>

(annotation) <#2 Retrieve the value of the private data field through type refelection.>

(annotation) <#3 Another safety check to make sure we are deserializing the correct object type.>

(annotation) <#4 Set the value of the private field through the reflection API.>

(annotation) <#5 Return the object after all the values are set.>

GetObjectData()

This GetObjectData() implementation looks very much like the GetObjectData() method in the example for the ISerializable interface. The only difference is that the serialized object is passed in as a parameter. The SerializationInfo object serves once more as the container for all the data we want to serialize. We call the AddValue() method to add the objects we want to serialize to the container. The SerializationInfo object will do everything else: check if any surrogates are registered for the added objects, check the objects for ISerializable and finally hand everything off to the formatter object. The formatter classes then handle all the gritty details about how the objects within the SerializationInfo are persisted and recreated upon deserialization. When it is time to deserialize the object we can retrieve all the stored values through the various Get* methods from the SerializationInfo object passed to SetObjectData(). Retrieving objects by calling GetValue() will also ensure that all retrieved objects are properly deserialized as well.

Our surrogate class above accesses the private field of the NonSerializable class through reflection. Sometimes this might be our only solution to properly handle 3rd party classes, but in general we should design serializable classes and surrogates to avoid reflection in favor of properties for example. Accessing fields through reflection bears a huge overhead compared to direct access or access through properties. Reading a private field through reflection, for example, can be more than 150x slower than reading it through a property.

SoapFormatterWithSurrogate

The last step before we can serialize and deserialize objects with our great, new surrogate is to create a serialization formatter and register the surrogate with it. The follwing example creates a custom formatter class that can always serialize objects of the NonSerializable class. The SoapFormatterWithSurrogate wraps the SoapFormatter class, and performs the registration of the surrogate and the surrogate selector in the constructor. First, we register the surrogate with a SurrogateSelector and specify the scenarios in which the formatter should delegate all action to this surrogate. Our example calls AddSurrogate() method with a StreamingContext object initialized with StreamingContextStates.All to register the surrogate for all serialization scenarios because the NonSerializable class can never be serialized on its own. Finally we pass the SurrogateSelector to the constructor of the SoapFormatter object and the formatter is ready to go. Every time a NonSerializable object is serialized (and deserialized) with a SoapFormatterWithSurrogate, the surrogate will automatically handle persisting and restoring the data.

24        Listing 12.5: Registering a SerializerSurrogate.

using System.Runtime.Serializtion;

public class SoapFormatterWithSurrogate

{

  private SoapFormatter _Formatter;

  public SoapFormatterWithSurrogate()

  {

    SurrogateSelector selector = new SurrogateSelector();

    selector.AddSurrogate( typeof( NonSerializable ),

      new StreamingContext( StreamingContextStates.All ),

        new NonSerializableSurrogate() );

    _Formatter =

      new SoapFormatter( selector,

        new StreamingContext( StreamingContextStates.All ) );

  }

  public void SerializeWithSurrogate(Stream destination,

    NonSerializable obj)

  {

    _Formatter.Serialize( destination, obj );

  }

  public NonSerializable DeserializeWithSurrogate(Stream source)

  {

    return (NonSerializable)_Formatter.Deserialize( source );

  }

}

Summary

Object serialization in the .NET Framework is valuable tool, not just in XML enabled .NET applications. This chapter demonstrated how we can develop serializable classes and how we can apply different techniques to override serialization behavior built into a class. The serialization format was not important in this chapter, because what learned is independent of the format. Yet it was important to understand the different aspects of serializable objects before we focus on serializing objects with the SoapFormatter. The SoapFormatter serializes objects into SOAP messages or parses SOAP messages and extracts serialized objects from the message.


Rate this article on a scale of 1 to 10

Your vote :  


 

Recent Jobs

An immediate job opportunity as a B
Software Developers Needed in Charl
Sr. Software Engineer - Analytics
Immediate Mainframe openings for Ch
Immediate TANDEM-TAL openings for C

View all Jobs (Add yours)
View all CV (Add yours)



answering service
online fax service
swimming pool contractor
conference calling
water softener
Teleconference
Host Department NOLIMIT Web Hosting
MSN
sunglasses


    Email TopXML  

Front Page Daily Stuff TopXML Forum XML blogs XML Newsgroups BizTalk Biztalk Utilities Biztalk Utilities Tutorial B2B SAP XML Microsoft .NET Dotnet System XML Soapformatter SQLXML XMLserializer XQuery PHP PHP SimpleXML PHP XML Dom PHP XML RPC PHP XSLT Java Java Java XML Xalan Microsoft ASP ASP Schemas XML SQL Server XML XMLDom XSL XSL Tutorial XSLT Stylesheets General Javascript CSS XHTML WAP