DataContractSerializer Basics

Basics of using DataContractSerializer independent of WCF services

The DataContractSerializer class serializes and deserializes an instance of a type into an XML stream or document using a supplied data contract. You do not need to be using WCF to take advantage of this class.

Namespace: System.Runtime.Serialization
Assembly: System.Runtime.Serialization (in System.Runtime.Serialization.dll)

Many developers assume that the DataContractSerializer is only for use with WCF Services. This is not true. You can use the DataContractSerializer class to serialize and deserialize instances of a type into an XML stream or document for any purpose. The only requirement is to apply the DataContractAttribute attribute to classes, and the DataMemberAttribute attribute to class members to specify properties and fields that you want to be serialized.

To use the DataContractSerializer, you first create an instance of a class and an object appropriate to writing or reading the format -- for example, an instance of the XmlDictionaryWriter. Then you call the WriteObject method to persist the data. To retrieve data, you create an object appropriate to reading the data format (such as an XmlDictionaryReader for an XML document) and call the ReadObject method.

You can also set the type of a data contract serializer using the <dataContractSerializer> element in a client application configuration file.

Annotating Classes for Serialization or Deserialization

The DataContractSerializer is used in combination with the DataContractAttribute and DataMemberAttribute classes. To set up a class for serialization, apply the DataContractAttribute to the class. For each member of the class that returns data that you want to serialize, you must apply the DataMemberAttribute. You can serialize fields and properties, regardless of accessibility: private, protected, internal, protected internal, or public.

The final format of the XML does not need not be text. The DataContractSerializer writes the data as an XML infoset, which allows you to write the data to any format recognized by the XmlReader and XmlWriter. Microsoft recommends that you use the XmlDictionaryReader and XmlDictionaryWriter classes to read and write, because both are optimized to work with the DataContractSerializer.

NOTE: If you are creating a class that has fields or properties that must be populated before the serialization or deserialization occurs, you can use callback attributes, check out Version Tolerant Serialization Callbacks on MSDN.

Adding to the Collection of Known Types

When you serialize or deserialize an object, it is required that the type is "known" to the DataContractSerializer. Begin by creating an instance of a class that implements IEnumerable<(Of <(T>)>) (such as List<(Of <(T>)>)) and adding the known types to the collection. Then you create an instance of the DataContractSerializer using one of the overloads that takes the IEnumerable<(Of <(T>)>) (for example, DataContractSerializer(Type, IEnumerable<(Of <(Type>)>)).

Forward Compatibility

The DataContractSerializer also understands data contracts that have been designed to be compatible with future versions of the contract. Such types implement the IExtensibleDataObject interface. The interface features the ExtensionData property that returns an ExtensionDataObject object. For more information, you can review Forward Compatible Data Contracts on MSDN.

Here is a simple example of how to use the DataContractSerializer -- completely independent of Windows Communications Foundation. We'll have a simple Windows Forms app that uses a button and a multiline TextBox to display what we're doing. First, here is the class that applies the DataContract and DataMember attributes:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace DataContractSerializerDemo
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml;
// You must apply a DataContractAttribute or SerializableAttribute
// to a class to have it serialized by the DataContractSerializer.
[DataContract(Name = "Person", Namespace = "http://www.mypeople.com")]
class Person : IExtensibleDataObject
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int ID;
public Person(string newfName, string newLName, int newID)
{
FirstName = newfName;
LastName = newLName;
ID = newID;
}
private ExtensionDataObject extensionData_Value;
// this illustrates using the versioning ExtensionData property, which is not used in the example.
public ExtensionDataObject ExtensionData
{
get
{
return extensionData_Value;
}
set
{
extensionData_Value = value;
}
}
}
}

And here is the Form class that handles the demo:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace DataContractSerializerDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Test t = new Test( this);
t.Main();
}
}
public class Test
{
private static Form1 Form1;
private static MemoryStream writer = null;
public Test( Form1 form)
{
Form1 = form;
}
public void Main()
{
try
{
WriteObject();
ReadObject();
}
catch (SerializationException serExc)
{

Form1.textBox1.Text+="Serialization Failed";
Form1.textBox1.Text+=serExc.Message;
}
catch (Exception exc)
{
Form1.textBox1.Text+=
"The serialization operation failed: "+
exc.Message +exc.StackTrace;
}

}
public static void WriteObject()
{
List<Person> personList = new List<Person>();
Form1.textBox1.Text+=
"Creating a personList object and serializing it:\r\n";
Person p1 = new Person("Daddy", "Longlegs", 101);
Person p2 = new Person("Jack", "Spratt", 102);
Person p3 = new Person("Brad", "Pitt", 103);
personList.Add(p1);
personList.Add(p2);
personList.Add(p3);
writer = new MemoryStream();
DataContractSerializer ser =
new DataContractSerializer(typeof(List<Person>));

ser.WriteObject(writer, personList );
Form1.textBox1.Text += System.Text.Encoding.UTF8.GetString(writer.ToArray());
Form1.textBox1.Text += "\r\n";
writer.Seek(0, 0);// Always rewind to beginnning of stream!
}
public static void ReadObject()
{
// Note we re-use the MemoryStream as it has not been closed.
Form1.textBox1.Text += "===============================\r\n";
Form1.textBox1.Text+="Deserializing an instance of the object:\r\n";
XmlDictionaryReader reader =
XmlDictionaryReader.CreateTextReader(writer, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(List<Person>));
// Deserialize the data and read it from the instance.
List<Person> deserializedPerson =
(List<Person>)ser.ReadObject(reader, true);
reader.Close();
Form1.textBox1.Text+=String.Format("{0} {1}, ID: {2}",
deserializedPerson[0].FirstName, deserializedPerson[0].LastName,
deserializedPerson[0].ID);
Form1.textBox1.Text += "\r\n" +String.Format("{0} {1}, ID: {2}",
deserializedPerson[1].FirstName, deserializedPerson[1].LastName,
deserializedPerson[1].ID);
Form1.textBox1.Text += "\r\n" + String.Format("{0} {1}, ID: {2}",
deserializedPerson[2].FirstName, deserializedPerson[2].LastName,
deserializedPerson[2].ID);
}
}
}

When you run this and click the button, you'll see the following display:

Using the DataContractSerializer, you have serialized a collection of type Person into a MemoryStream, and then deserialized it back into a collection of type Person and displayed the results.

There is another good reason to become familiar with DataContractSerializer and its brethren: Often, developers will start by "designing XML" as if it were a business object, and find themselves later attempting to "make it fit" into some sort of object. That's backwards. Create the POCO entity first, and ask the DataContractSerializer to create your XML from it. You'll be assured that it will all "round trip", and you'll have the advantage of Business Domain Entities that can be used to build a back-end persistence layer- whether with Entity Framework, or tools such as NHibernate.

Think of different ways you can use this technique. I bet you can come up with several right away. You can download the Visual Studio 2008 solution here.


By Peter Bromberg   Popularity  (21995 Views)