In my first and second postings on serialization, I focused on the basics of the concept. This time around, I want to give you some additional tips that I learned the hard way. As always, the System.Runtime.Serialization namespace or System.Xml.Serialization namespace is required and all of this is applicable to all of the .Net languages (VB.Net, C#.Net, VBScript, etc… ). These code samples are Microsoft .Net Framework 4.0 source.
Transmitting Serialized Objects
I had the scenario where I had to serialize many objects (both binary and XML), transmit the data over a TCP Socket to a Windows Server and/Workstation (XP or Windows 7), and then deserialize the object. The problem that I ran into was knowing when I had received all of the serialized data – particularly when there was no significant gap in time between the end of one and the start of the next.
Type Determination
When deserializing an object, one must know the Class Type. I had the scenario where I was sending a variety of serialized types.
I resolved both of the above issues by including a header (of sorts) that includes the object type and length of data and wrapping the data with start-of-message/end-of-message tags. The following method allows passing in the object to be serialized and a ByReference header string. The method returns the serialized object (and the header information in the ByRef variable).
Public Shared Function SerializeXML(ByVal pObject As Object, _
ByRef pHeader As String) As String
Dim _xmlSerializer As XmlSerializer
Dim _xmlStream As StringWriter = New StringWriter
Dim _xmlSerializerNamespace As XmlSerializerNamespaces
‘ This simply clears the XMLNS attribute from the XML document
_xmlSerializerNamespace = New XmlSerializerNamespaces
_xmlSerializerNamespace.Add(“”, “”)
_xmlSerializer = New XmlSerializer(pObject.GetType)
_xmlSerializer.Serialize(_xmlStream, pObject, _xmlSerializerNamespace)
Dim xmlSize As Integer = _xmlStream.GetStringBuilder.Length
pHeader = String.Format(“${0}|{1}|”, xmlSize, _
String.Concat(pObject.GetType.ToString(), “, “, _
pObject.GetType.Assembly.ToString.Substring( _
0, pObject.GetType.Assembly.ToString.IndexOf(“,”))))
Return _xmlStream.GetStringBuilder.ToString
_xmlStream.Close()
_xmlStream = Nothing
End Function
When transmitting these serialized objects via a TCP Socket, the header is prepended and the whole string wrapped with the start of message/end of message tags. The exact value of these tags is not important, only that they are unique. This can be a little tricky as serialized data is pretty unpredictable. I elected to use “$SOM$” and “$OEM$”.
At the receiving end, I continuously read the socket and process the received data after each read of the buffer. When a complete message is detected (includes both start of message and end of message), it is handed off to a processing thread. This thread splits off the header information, ensures that length of the data matches what is expected, and then deserializes the object using the specified Type information.
Public Shared Function DeserializeXML(ByVal pHeader As String, _
ByVal pObjString As String) As Object
Dim _xmlSerializer As XmlSerializer
Dim _header() As String = pHeader.Split(“|”)
Dim _xmlSize As String = _header(0)
Dim _objectType As String = _header(1)
Dim _assembly As String = _header(2)
Dim _object As Object
‘ Create a new StringReader to pass to Deserialization routine
Dim _textReader As StringReader
_textReader = New StringReader(pObjString)
Dim _type As Type = Type.GetType(_objectType)
If IsNothing(_type) Then
If _objectType.IndexOf(“,”) > -1 Then
_objectType = _objectType.Substring(0, _objectType.IndexOf(“,”))
_type = Type.GetType(_objectType)
End If
End If
If IsNothing(_type) Then
‘ Cannot deserialize…
_object = Nothing
Else
_xmlSerializer = New XmlSerializer(_type)
_object = _xmlSerializer.Deserialize(_textReader)
End If
_xmlSerializer = Nothing
Return _object
End Function
The return from this routine is your deserialized object. At that point, you can check it’s type to determine what to do with it. If using Interfaces, as you should, you can also call methods on the object if it supports a particular interface.
Leave a Reply