//Sunday 25 November 2007

Xml Serialization in C#

In a number of recent projects we have had to expose web services to third parties. This requires discipline in agreeing and sticking to a XML schema for your communication.

BaseSerializableObject
To make sure our classes keep in step with our schemas we utilise a base serializable object class which provides methods for converting our objects to and from XML. Each object then implements a FromXml method that validates the XML against the appropriate schema before deserialization.
    public XmlDocument ToXml()
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(sb, settings);
XmlSerializer serializer = new XmlSerializer(this.GetType());
serializer.Serialize(writer, this);
XmlDocument output = new XmlDocument();
output.LoadXml(sb.ToString());
return output;
}

protected static SerializableObject FromXml(Type type, XmlDocument input, XmlSchema schema)
{
byte[] data = Encoding.Unicode.GetBytes(input.OuterXml);
using (MemoryStream ms = new MemoryStream(data))
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
settings.Schemas.Add(schema);
XmlReader reader = XmlReader.Create(ms, settings);
XmlDocument validatingDoc = new XmlDocument();
// This will throw an error if the xml does not validate against the schema
validatingDoc.Load(reader);
// If we got this far then deserialize
ms.Position = 0;
XmlSerializer serializer = new XmlSerializer(type);
return (SerializableObject)serializer.Deserialize(ms);
}
}
Attributes
To enable you to dictate the way in which your objects are serialized you can specify XML attributes above your class declaration and properties.
  • Serializable
    This attribute is essential for your class to be serializable and must appear above your class declaration.
  • XmlRoot
    This attribute allows you to specify information about the root element of the XML document that will be the output of your serialization.
  • XmlAttribute
    This attribute allows you to specify the way in which a property of your object is serialized as an XML element.
  • XmlElement
    This attribute allows you to specify the way in which a property of your object is serialized as an XML element.
  • XmlIgnore
    This attribute tells the serializer not to include the property in the serialization.
  • XmlArray, XmlArrayItem
    These attributes tells the serializer how to name array elements.

Example

The following is a rather contrived example to demonstrate these concepts:

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlSerialization
{
[Serializable, XmlRoot(ElementName = "objectXml")]
public class MySerializableObject : SerializableObject
{
private int _integerOne;
private int _integerTwo;
private int _integerThree;
private int _integerFour;
private string _stringOne;
private string _stringTwo;
private string _stringThree;
private string _stringFour;
private MySerializableObject[] _children;

public MySerializableObject()
{
}

public MySerializableObject(int integerOne,
int integerTwo,
int integerThree,
int integerFour,
string stringOne,
string stringTwo,
string stringThree,
string stringFour)
{
_integerOne = integerOne;
_integerTwo = integerTwo;
_integerThree = integerThree;
_integerFour = integerFour;
_stringOne = stringOne;
_stringTwo = stringTwo;
_stringThree = stringThree;
_stringFour = stringFour;
}

public static MySerializableObject FromXml(XmlDocument objectXml)
{
// Load embedded Xml schema from assembly
XmlSchema schema = XmlSchema.Read(Assembly.GetAssembly(typeof(MySerializableObject)).GetManifestResourceStream("XmlSerialization.schemas.MySerializableObject.xsd"), null);
// Deserialize object from XML provided (if XML passes validation)
MySerializableObject obj = (MySerializableObject)SerializableObject.FromXml(typeof(MySerializableObject), objectXml, schema);
return obj;
}

[XmlElement(ElementName = "numberTwo", Order = 4)]
public int IntegerOne
{
get
{
return _integerOne;
}
set
{
_integerOne = value;
}
}

[XmlIgnore]
public int IntegerTwo
{
get
{
return _integerTwo;
}
set
{
_integerTwo = value;
}
}

[XmlElement(ElementName = "numberOne", Order = 3)]
public int IntegerThree
{
get
{
return _integerThree;
}
set
{
_integerThree = value;
}
}

[XmlAttribute(AttributeName = "integerAttribute")]
public int IntegerFour
{
get
{
return _integerFour;
}
set
{
_integerFour = value;
}
}

[XmlElement(ElementName = "textTwo", Order = 2)]
public string StringOne
{
get
{
return _stringOne;
}
set
{
_stringOne = value;
}
}

[XmlIgnore]
public string StringTwo
{
get
{
return _stringTwo;
}
set
{
_stringTwo = value;
}
}

[XmlElement(ElementName = "textOne", Order = 1)]
public string StringThree
{
get
{
return _stringThree;
}
set
{
_stringThree = value;
}
}

[XmlAttribute(AttributeName = "stringAttribute")]
public string StringFour
{
get
{
return _stringFour;
}
set
{
_stringFour = value;
}
}

[XmlArray(ElementName = "kids", Order = 5)]
[XmlArrayItem(ElementName = "kid")]
public MySerializableObject[] Children
{
get
{
return _children;
}
set
{
_children = value;
}
}
}
}

//Monday 5 November 2007

Welcome to the sourcemotion blog

Welcome to the new sourcemotion blog. I'm going to be posting articles about IT, specifically web development using Microsoft technologies. I hope people find it useful. I think it will be useful and interesting for me to have a log of the sorts of things I have been working on and the solutions we have come up with.

SyntaxHighlighter