Click here to Skip to main content
Click here to Skip to main content

Having fun with the XmlSchemaProvider: Serializing object trees

, 9 May 2006
Rate this:
Please Sign up or sign in to vote.
Learn how to serialize object trees into SOAP and back again.

Introduction

About a year ago, I became very enthusiastic. I found a new attribute in the framework which allows me to determine the WSDL contract which describes my objects. Used in conjunction with the IXmlSerializable interface, I can also make sure the serializer pumps out the correct XML, corresponding to the custom XML-Schema inside the WSDL. Why is this so important? The default XmlSerializer requires all fields to have public get / set properties. This means my Product object needs a public get/set ID property. I personally didn’t want a settable ID property, because it is the never-changing primary key for that object. Furthermore, I did not want to change the public interface of my objects just because they’ll be serialized into a SOAP message. Using XmlSchemaProvider with IXmlSerializable, you can fix all this; keep only the getter, and still serialize the ID.

Now, all of this sounds good of course, and there are various samples on the internet showing how you can use these two classes to serialize your own ‘Product’ objects. However, the examples I found only show how to serialize a single object, not a tree of objects, such as an Order-OrderItem combination or Order-Customer-Address. Is this more difficult then? Well, yeah, a tad-bit, because you’ll have to share the XML-Schema definition somehow.

Not finding the answer on the web, I dug into this problem myself, like I did about a year ago. The only difference is that this time, I have a working solution which I want to share with you guys.

Serializing an Order object

The following example will show how you can utilize XmlSchemaProvider for serializing an object-tree. This example uses two objects, Order and Product, with an Order containing multiple Products. The Product class contains a readonly ID property, and has a private default constructor. The Order class contains a readonly List<T> of Products and also a readonly ID property. Here, I’ll give attention only to the Order class, the Product class is not that interesting after reading up on the subject. Check the code to see how it has been built.

The Order class I’ll describe a bit further, since that’s where the magic happens.

The basic class definition for Order is as follows:

[XmlSchemaProvider("GetOrderSchema")]
public class Order : IXmlSerializable
{
    int _id;
    List<Product> _products = null;

    public int ID { get;}
    public List<Product> Products { get;}
}

To supply the correct schema to the serialization infrastructure, the XmlSchemaProvider attribute is applied to the class. Inside the method tied to the XmlSchemaProvider attribute, the schema for the Order class is constructed using the System.Xml object model, also the Product is included in the schema for the Order class using an XmlSchemaInclude:

public static XmlSchemaComplexType GetOrderSchema(
              XmlSchemaSet schemas)
{
    string tns = "http://diveinit.nl/schemas/test";
    string xmlns = "http://www.w3.org/2001/XMLSchema";

    XmlSchema schema = new XmlSchema();
    // Include the product schema as an include so it can
    // be referenced in the order schema.
    XmlSchema productSchema = Product.Schema;
    XmlSchemaInclude productSchemainclude =
        new XmlSchemaInclude();
    productSchemaInclude.Schema = productSchema;
    schema.Includes.Add(productSchemaInclude);
    ...
    ...
  //-- The rest of the method is ommited for brevity--//
}

Now that the WSDL has been set up correctly, it is time to serialize and deserialize the Order class. This is done using the IXmlSerializable interface, which requires you to build three methods. First up is the serialization using the WriteXml method. This method is also responsible for serializing the Product objects contained in the Order.

void IXmlSerializable.WriteXml(XmlWriter writer)
{
    string ns = "http://diveinit.nl/schemas/test";
    writer.WriteElementString("id", ns, _id.ToString());
    ICollection<Product> products = Products;
    if (products.Count > 0)
    {
        writer.WriteStartElement("ProductCollection");
        foreach (Product product in products)
        {
            writer.WriteStartElement("Product");
            ((IXmlSerializable)product).WriteXml(writer);
            writer.WriteEndElement();
        }
        writer.WriteEndElement();
    }
}

The root element is supplied for you, this means you don’t have to write this yourself inside the WriteXml method. So the first item to write is the private ID field of the Order object. Next up are all the Products contained in the Order. They are contained inside an extra element called "ProductCollection". Make sure to use the WriteXml method of the Product object so that is serialized correctly too.

Now for some deserialization. This is a bit more difficult because you do not know how many Products the Order contains, when deserializing. The XmlReader provides a handy method to determine this, which is called IsStartElement.

void IXmlSerializable.ReadXml(XmlReader reader)
{
    string ns = "http://diveinit.nl/schemas/test";
    reader.ReadStartElement();
    _id = reader.ReadElementContentAsInt("id", ns);
    if (reader.IsStartElement("ProductCollection", ns))
    {
        reader.ReadStartElement();
        while (reader.IsStartElement("Product", ns))
        {
            Product product = new Product();
            ((IXmlSerializable)product).ReadXml(reader);
            Products.Add(product);
        }
    }
    reader.ReadEndElement();
}

That is it. A fully functional example on how to use XmlSchemaProvider in conjunction with IXmlSerializable for all your serialization needs!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Wouter van Vugt
Web Developer Code Counsel
Netherlands Netherlands
Wouter van Vugt is a Microsoft MVP with Office Open XML technologies and an independent consultant focusing on creating Office Business Applications (OBAs) with SharePoint, the Office 2007 system and related .NET technologies. Wouter is a frequent contributor to developer community sites such as OpenXmlDeveloper.org and MSDN and has published several white papers and articles as well a book available on line titled Open XML: the markup explained. Wouter is the founder of Code-Counsel, a Dutch company focusing on delivering cutting-edge technical content through a variety of channels. You can find out more about Wouter by reading his blog and visiting the Code-Counsel Web site.

Comments and Discussions

 
Generalvery nice! Pinmemberspamcatcher66617-May-06 6:35 
I've been nothing but confused until now. Everyone does have examples on how to do it, but some have element based, some have type based, some have localized elements (?A?! how do I work with that?! haha) But you're the only one with the trees. Thanks a bunch. I really like your paradigm of exposing the schema via a static property, that will no doubt come in handy in other ways someday too.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 9 May 2006
Article Copyright 2006 by Wouter van Vugt
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid