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.
There is not much to the InsertJob class either, partly
because we did not code the actual insert operation. However, we don’t care
about the insert operation, we are much more interested what an instance of
this class looks like when the SoapFormatter serializes it. Let’s note that the job
class stores a user object and implements a special interface to run the job
once it was deserialized. Now let’s move on and examine a serialized InsertJob
object.
Listing A SOAP message with a serialized object in the
body.
(annotation) <#1 These namespaces identify SOAP
version 1.1.>
(annotation) <#2 This declaration identifies the CLR
version.>
(annotation) <#3 Signal compliance with the section 5
serialization guidelines.>
(annotation) <#4 The serialized object forms the root
element within the SOAP body.>
(annotation) <#5 The element name and the namespace
completely identify the serialized type and its assembly.>
(annotation) <#6 The _NewUser field created a
reference element.>
(annotation) <#7 The element name and the namespace
completely identify the serialized type and its assembly.>
(annotation) <#8 Value types are embedded.>
(annotation) <#9 Reference types are references.>
This listing above looks, feels and smells like a complete
SOAP message with an <Envelope>
and a <Body>
tag and the namespace declarations to identify a SOAP Version 1.1 message. The
object we serialized is the first element in the SOAP body. The element is
named after the object’s class InsertJob and it declares an odd-looking namespace. The
first part of the namespace name up until nsassem/ indicates that we are
looking at an object that was serialized from a .NET assembly. The next portion
of the name reflects the .NET namespace of our InsertJob class in listing 13.4. The
next part of the name contains some HTML encoded characters. Once we decode the
name we can see the fully qualified assembly name: Objects, Version:1.0.0.1, Culture:neutral,
PublicKeyToken:null with the assembly’s version number, culture
information and, if present, the public key token of the assembly’s strong name.
In short, this odd-looking namespace declaration contains everything the .NET
runtime needs to locate and load the correct assembly when the object is
deserialized. The SOAP standard does not exactly mandate to encode the type
information like this. It is Microsoft’s solution to encode detailed type
information in a SOAP message in way that is still compatible with the
standard. The SoapFormatter
deserializes reads these namespace declarations when it deserializes a SOAP
message stream and attempts to load an assembly compatible with the information
in the namespace name. It will throw a System.Runtime.Serialization.SerializationException
if it can not locate a compatible assembly. How exactly the
runtime locates assemblies and determines compatibility is enough material for
another chapter. It is enough for us to know that two assemblies are compatible
if name, culture, strong name and version match. I refer you to the .NET
Framework documentation for more details.
Let’s go back to examining
the message. The public _NewUser
field of the InsertJob
class is represented as a child element of the <InsertJob> element with the
same name as the field. However, the fields of the User class are not directly embedded
as child nodes inside the <NewUser>
element. Instead <_NewUser>
references another element in the SOAP message’s body through an href attribute.
In our example here, the referenced User element is the next sibling of
the <InsertJob>
element inside the <Body>.
Again, the element name and a namespace declaration provide detailed
information about the serialized object type to the SoapFormatter. Inside the User element we
do not find any elements corresponding to the public properties, only the data
stored in the private fields. The SoapFormatter only serializes private and public fields,
to take a complete snapshot of the object. Serializing properties is not
necessary because the formatter persists all fields. The SoapFormatter accesses private fields
through reflection, but to do so it requires special security permissions as we
have seen.
If you paid good attention, you noticed that the <_Name>
element has an id attribute, like <User> and <InsertJob> did, but the <_Id> tag
does not. Maybe you still remember how I mentioned that int was a value type and string a
reference type? Here is where this difference matters. The SOAP 1.1 standard
requires in section 5 that fields of reference types have to be serialized as
“independent elements” referenced by their id attribute. In other words, all
objects of reference types in the serialized object graph have to appear as
immediate children of the <Body>.
Value types, which cannot be referenced from other objects, should be
serialized as embedded content without an id attribute.
BUG WARNING: The output of the SoapFormatter does not validate
against the SOAP 1.1 schema published at http://schemas.xmlsoap.org/soap/envelope/.
According to this schema the SOAP-ENV:Envelope can not have any attributes from the
SOAP-ENV namespace. This conflicts with the standard document which declares
the encodingStyle
attribute within Envelope
section of the document and shows placement of the SOAP-ENV:encodingStyle attribute on
the Envelope
element. The SoapFormatter
follows the standard document and places the encodingStyle attribute on the
Envelope element. We have to manually remove the encodingStyle attribute if we send
SOAP messages generated with the SoapFormatter to WebServices that validate incoming
messages against the published SOAP schema.