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.
Looking at this complex format begs the question how the XmlSerializer
generates a DiffGram when it serializes a DataSet. When the XmlSerializer turns
a DataSet into XML it will not retrieve any values from any property. Instead
it lets the object control its own serialization. The DataSet implements the
unsupported interface System.Xml.Serializarion.IXmlSerializable shown
19
Listing 10.17 The
IXmlSerializable interface.
public interface IXmlSerializable
{
XmlSchema GetSchema();
void ReadXml(XmlReader
reader);
void WriteXml(XmlWriter
writer);
}
Whenever Serialize() detects that an object implements this
interface it will pass the XmlWriter to the object and does not attempt to
serialize the object. Likewise, Deserialize() passes the XmlReader instance to
the object and lets the object parse the XML stream.
BIG, FAT WARNING: IXmlSerializable is documented as “for internal
use only”. Microsoft is free to change this interface at any time. Keep this in
mind if you should ever decide to implement this interface yourself.
Sometimes implementing IXmlSerializable may be the only way to
serialize a class, so let’s take a quick look at the interface,
method-by-method:
GetSchema() is called when the constructor is creating a type mapping for
the class. You need to return an XmlSchema object
that describes the XML format created by WriteXml().
ReadXml(XmlReader
reader) is called from the Deserialize() method right after it was able to
identify a type that implements IXmlSerializable in the XML stream. It
constructs the object and calls ReadXml() on it. The XmlReader is positioned at
the first child node of the object’s root. You have to read the XML stream and
set your object’s fields yourself. The details about reading XML streams with
classes derived from XmlReader.
WriteXml(XmlWriter
writer) is called from the Serialize() method when the XmlSerializer detects
that an object that implements IXmlSerializable. The writer is positioned after
the root node for the object when it is passed to the WriteXml() method.
With those three methods you can completely control how
serialization and deserialization of a class takes place. You can find an example how to implement
IXmlSerializable in our web site, if you feel the urge to explore the power of
this interface in more depth. Again: implement this interface only as a last
resort solution. Since you cannot assume that Microsoft supports this interface
in a later version of the .NET Framework, you must deploy your solution only in
environments where you can ensure the installed version of the .NET runtime
supports this interface.
We can control serialization of class at a number of levels.
First of all, we can express whether or not we intend a class to be serialized
when we develop it. At a finer-grained level of control, we can code classes to
take control over their serialization if the runtime’s serialization mechanism
is not appropriate and finally, we can override serialization for any given
class externally, by delegating the whole process to a different class. We will
learn about each of these options in this chapter.
There is only one true requirement for classes the SoapFormatter
can process: A class needs permission from its author to be serialized. This
permission is expressed by attaching the SerializableAttribute from the System
namespace a class. Any time we add the Serializable attribute to a class like
this:
[System.Serializable]
public class SerializableClass
{
}
we let other developers know that we gave our OK to them
serializing our class. The serialization formatters check each object they
serializes for this attribute and throw a SerializationException if the
attribute is not present. If the attribute is present the formatter will
persist the state of every(!) field, public and private alike, to the specified
output stream. The fields of a [Serializable] object have to reference objects
that are themselves [Serializable], or else we must explicitly exclude them
from the generated SOAP message (we will learn how to do that in the following
section). All classes higher up in the inheritance hierarchy, i.e. classes we
derive from, have to have serialization clearance as well. Otherwise we could
easily circumvent the class authors’ intent and make a non-serializable class
serializable by simply deriving from it.
Many classes in the .NET Framework libraries are marked with this
attribute, in fact, all primitive types in the System namespace are. Check the
.NET Framework documentation to see which ones are and which ones are not. The
notable exception on the long list of serializable classes, are the classes in
the System.Xml namespace, XmlDocument and XmlNode for example. While they
provide excellent support for serialization with the XmlSerializer, we cannot
serialize them with a serialization formatter. We have to code serialization
for these classes explicitly.
Some classes do not want to serialize all their fields either
because they reference non-serializable objects,
because we want to prevent
sensitive information, like passwords or encryption keys, to show up in the
output, or
because it does not make sense.
Serializing delegates and events,
for example, is usually not interesting because they are tied to the application
executing when the object is serialized. For all these cases the System
namespace provides the NonSerializedAttribute. We can attach it to the fields
we want to exclude from the serializer output as shown in the following code
fragment:
[Serializable]
public class SerializableClass
{
[NonSerialized]
public string
_MySuperSecretPassword;
// …
}
When the SoapFormatter serializes an instance of the
SerializableClass class, there will be no reference to the MySuperSecretPassword
member. Accordingly, NonSerialized fields are initialized to null in objects
created by deserialization.