« May 2006 | Main | July 2006 »

June 2006

Shaping data for the DataContractSerializer (and thus WCF)

The other day we came across this small thing while writing some sample code for our docs.

We can control the way our CLR arrays are serialized in a well-known way by using XmlSerializer and the XmlArrayAttribute and XmlArrayItemAttribute attributes.
For example having a type like this...

[XmlType(TypeName="Family")]
public class Family
{
  [XmlArray(ElementName = "Members")]
  [XmlArrayItem(ElementName = "Name")]
 
public string[] Members;
}

...could produce XML as follows by leveraging XmlSerializer.

<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Members>
    <Name>A</Name>
    <Name>B</Name>
    <Name>C</Name>
    <Name>D</Name>
  </Members>
</Family>

Now, if we define a bare WCF data contract to represent the same family it would look like this:

[DataContract]
class Family
{
  [DataMember]
  public string[] Members;
}

The DataContractSerializer (DCS) produces the following XML for an instance of the Family class:

<Family xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Client">
  <Members xmlns:d2p1="
http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d2p1:string>A</d2p1:string>
    <d2p1:string>B</d2p1:string>
    <d2p1:string>C</d2p1:string>
    <d2p1:string>D</d2p1:string>
  </Members>
</Family>

But if we want to make it look equivalent to the XML generated for the XmlSerializer-based Family document instance, how could we do that?

There is a solution. Looking at the following screenshot from Lutz's fantastic Reflector we can see there are some attributes we can use to massage the XML spit out by DCS.

WCF's DataContractSerializer attributes

So, instead of using an array, you need to use a collection type marked with the CollectionDataContractAttribute (you can derive a type from an existing collection type and add the attribute). The attribute has properties that can be used to customize array item names, etc.

E.g.:

[DataContract(Name="Family")]
class Family
{
  [DataMember(Name="Members")]
  public MemberList Members;
}

[CollectionDataContract(ItemName="Name")]
class MemberList : List<string> { }


Feel free to download a small demo solution for WinFX Beta 2.