BizTalk Utilities CV ,   Jobs ,   Code library  
 
Home Page
WCF, WS, SOAP
Serializing an Object Graph
The SoapFormatter
Runtime Object Serialization
Importance of a UDDI based Service Registry
BizTalk and WCF: Part V, Publishing Operations Patterns
BizTalk and WCF: Part IV, Attachment Patterns
BizTalk and WCF: Part III, Transaction Patterns
BizTalk and WCF: Part II, Security Patterns
BizTalk and WCF: Part I, Operation Patterns
Accessing UDDI using Apache Scout APIs
Storing state in an XML property bag
UDDIExplorer
XslTransport for PocketSOAP
Kafka - XSLT SOAP Toolkit
VB Web services Proxy Generator
Using msxml3 with Web Storage System
Getting started with SOAP
Calling an Web service from a Managed C++ project
How to access asyncronously from C# an web service
What is XML-RPC?
<< Uncategorized
XALAN >>

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 :358

 

Deserializing an Object Graph

Now that we can send an object as a SOAP message and we know what the message contains, we can go on to develop the next class for our SOAP-over-message-queues library. This class will process the SOAP messages coming in on a message queue, deserialize the objects contained in the message and execute a method on the deserialized object.

The best class to interpret the contents of the SOAP message is the same class that already created the message for us: The SoapFormatter. It exposes two overloaded versions of the Deserialize() method.

Table The two overloaded versions of the Deserialize() method read a SOAP message from a stream and return the object graph stored in the body. The second version allows us the register a method to receive notifications about application headers in the SOAP message.

Method

Description

public object Deserialize( Stream s )

Deserializes an object graph in the body of a SOAP message from the current position of the stream.

public object Deserialize( Stream s, HeaderHandler h )

Deserializes an object graph in the body of a SOAP message from the current position of the stream. A HeaderHandler delegate can specify a method to invoke to take action on the message headers before the object in the body is deserialized. The delegate can be null.

Both versions read SOAP messages from the current position of a stream and recreate the object graph from the message body. One lets us register a call-back method to process SOAP headers in the message. We will focus on the simple case without headers first. Later on section section 13.4 will show us how we can add SOAP Headers to a message and retrieve them with a HeaderHandler delegate.

Developing the Receiver class

Let’s apply our newly acquired knowledge about the Deseralize() method to write the SoapMessageReceiver class to read SOAP messages from a message queue and extract the objects within the message. The design of the receiver class is very similar to the design of the SoapObjectSender class from the previous section. It encapsulates all the details of message queuing and serialization. A receiver object listens on one and the same queue for its lifetime and keeps a formatter object to extract the objects in the received objects. The next code listing shows the receiver class.

Listing 13.5 The receiver class processes SOAP messages from a message queue

public class SoapObjectReceiver

{

  protected MessageQueue _ReceivingQueue;

  protected SoapFormatter _Formatter;

  public SoapMessageReceiver(string queueName)

  {

    _ReceivingQueue = new MessageQueue(queueName);

    _Formatter = new SoapFormatter();

  }

  private void ProcessStream( Stream stream )

  {

    IQueuedJob job = _Formatter.Deserialize( stream ) as IQueuedJob;|#1

    if( null != job )

    {

      job.Run();

    }

  }

  public void ReceiveObject( int timeout )

  {

    Message queueMessage;

    try

    {

      queueMessage = _ReceivingQueue.Receive(

        new TimeSpan( 0, 0, 0, timeout, 0 ) );

      Console.WriteLine( "Message received." );

      ProcessStream( queueMessage.BodyStream );

    }

    catch (MessageQueueException ex)

    {

      // Handle no message arriving in the queue.

      if ( MessageQueueErrorCode.IOTimeout

        != ex.MessageQueueErrorCode )

      {

        Console.WriteLine( ex.Message );

      }        

    }

  } // ReceiveObject()

} // class SoapMessageReceiver

(annotation) <#1 Reconstruct the object graph with the Deserialize() method. >

 

The majority of the code for this class is related to message queuing, not parsing the message or the deserialization. That work is already done for us within the Deserialize() method of the SoapFormatter. We do not need to provide any additional information to the method, because Serialize() embedded all information necessary to recreate an object graph within the message. Once Deserialize() reads the type information, the SoapFormatter loads the required assembly, if it is not already loaded, creates an object and initializes the object’s members with the classes in the System.Reflection namespace of the .NET Framework. Let’s examine each of these steps closer to gain better understanding what goes on inside the Deserialize() method.

Resolving Assembly Names

The first step deserializing an object is to resolve the assembly information in the SOAP message. By default the SoapFormatter will store the fully qualified assembly name, containing culture, version, and the strong name key token in the message. Deserialize() will attempt to locate an assembly that is compatible with the information in the SOAP message. Including all these different pieces of information in the compatibility check protects us from versioning problems. It ensures that the SoapFormatter deserializes an object only if it can load an assembly compatible with the one the object was serialized from. The price we pay for this protection is very tight configuration management to keep all machines that serialize and deserialize our messages on compatible assembly versions. If we are absolutely confident that we want (or have) to trade in some risk of versioning problems for more flexibility we can instruct the SoapFormatter to only persist a simple assembly name. When we set the AssemblyFormat property to FormatterAssemblyStyle.Simple the generated messages identify assemblies only by their name. The SoapFormatter does not consider culture, version and strong name to determine compatibility. With this setting a namespace attribute in listing 13.4 would be reduced to:

http://schemas.microsoft.com/clr/nsassem/Christoph.SoapMQ.Shared/Objects

Table Values of the FormatterAssemblyStyle enumeration for the AssemblyFormat.

FormatterAssemblyStyle Value

Description

Simple

The assembly description consists of the assembly name only.

Full

The assembly description includes assembly name, culture, version and public key token.

It is important for us to know that we have to set the AssemblyFormat property to the same value on both, the serializing and the deserializing formatter because Deserialize() will default to the more restrictive behavior. It will always consider the fully qualified name to load an assembly if it is present in the message even if we set the AssemblyFormat property to FormatterAssemblyStyle.Simple. With the AssemblyFormat property set to FormatterAssemblyStyle.Full the SoapFormatter will not process a message unless it contains the full type information.

Step two after loading the required assembly is to obtain a Type object for the object we are going to deserialize. With the information and the Type’s name and its .NET namespace from the SOAP message Deserialize() can query the assembly for the Type object through reflection. The SoapFormatter then instantiates an object from the Type and finally initializes all fields from the data in the message.

Controlling Assembly and Type Resolution Through Binders

The SoapFormatter offers a hook to control locating types and assemblies, if we ever need to change the default resolution for assemblies and types. We can assign a custom SerializationBinder object that will take over loading assemblies and locating types. A custom SerializationBinder must inherit from the abstract SerializationBinder class and override the BindToType() method.

Table 13.5 A SerializationBinder has to implement the BindToType() method. The method locates assemblies and resolves type names.

Method

Description

public abstract Type BindToType(

   string assemblyName,

   string typeName

)

Resolves assembly and type names and returns the Type object after a successful resolution.

If we register a custom binder with a formatter, it will call the binder’s BindToType() to obtain a Type object for each object in the processed SOAP message. This is our chance to substitute assemblies or types that are not available because they were retired from the system, for example, or because we refactored classes into different namespaces or assemblies or because we do not have access to the original assemblies. In all these scenarios we can implement BindToType() to map an assembly and/or a type name to a different assembly or type. Once we determined what type to bind to our BindToType() implementation has to return the corresponding Type object to the formatter. The formatter then creates an object from that Type and proceeds as normal.

Object Graph Reconstruction

Step three in the deserialization process is the reconstruction of the object graph. The SoapFormatter is facing some interesting problems now: Which constructor am I going to use for classes with more than one? Are there any side-effects from running a constructor that are not compatible with the serialized field values? What parameter values am I going to provide to a parameterized constructor? Because the formatter has no way to determine the correct solutions, it solves this problem by not using any constructor to create the object. It bypasses all the means of the .NET Framework for object instantiation and does some low-level magic to create a completely un-initialized object. Then it sets all the fields according to the information found in the SOAP message through the classes in the System.Reflection namespace.


Rate this article on a scale of 1 to 10

Your vote :  


 

Recent Jobs

Software Developers Needed in Charl
Sr. Software Engineer - Analytics
Immediate Mainframe openings for Ch
Immediate TANDEM-TAL openings for C
Immediate ASP.NET/C# Openings for C

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



it outsourcing
swimming pool builder
conference call for CA
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