dinsdag 3 juli 2012

XML Serialization with C#

There are a lot of ways to serialize and deserialize objects into xml strings. Some are easier than others, and some will give you headaches by unintelligible exceptions. In this blog I'll show you how I serialize and deserialize XML.

Let's first create basic object that we want to serialize:

public class MyObject
{
   public string Number{ get; set; }
   public string Status { get; set; }
   public bool IsSomething { get; set; }
}

When we want to serialize this object we basically have two serializers we can choose: XmlSerializer and DataContractSerializer. I prefer the latter. The best desciption of the differences between the two can be found here: XmlSerializer vs DataContractSerializer

When using DataContractSerializer we have to mark our object with DataContract, and all properties we want to serialize must be marked with DataMember, like this:

[DataContract]
public class MyObject
{
   [DataMember]
   public string Number{ get; set; }

   [DataMember]
   public string Status { get; set; }

   public bool IsSomething { get; set; }
}

As you can see the IsSomething property has no DataMember attribute, and therefore will not be serialized.

You can set the name of the class and properties in XML, like this:

[DataContract(Name = "myobject", Namespace = "")]
public class MyObject
{
   [DataMember(Name = "nr")]
   public long Number{ get; set; }

   [DataMember(Name = "status")]
   public string Status { get; set; }
}


Serialize object into xml string

The class MyObject can be serialized this way:

var myObject = new MyObject {Number = 97, Status = "complete"};

var stream = new MemoryStream();
var wr = XmlWriter.Create(stream);
var serializer = new DataContractSerializer(typeof (MyObject));
serializer.WriteObject(wr, myObject);
wr.Close();

Encoding utf8Encoder = new UTF8Encoding(false);
var result = utf8Encoder.GetString(stream.ToArray());

After running this code, result will look like this:

<?xml version="1.0" encoding="utf-8"?><myobject xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1"><nr>97</ nr ><status>complete</status></myobject >

The code is pretty straightforward, except for one thing:

Encoding utf8Encoder = new UTF8Encoding(false);
var result = utf8Encoder.GetString(stream.ToArray());

Why don't I simply do this:

var result = Encoding.UTF8.GetString(stream.ToArray());

The code above will put a Byte Order Mark at the beginning of the xml string. It can't be seen in the Visual Studio debugger, but if you copy-paste the result into a text editor it will look like this:

?<?xml version="1.0" encod[...]

The ? is the Byte Order Mark. If you try to deserialize an xml string with a Byte Order Mark you will get this exception:

Data at the root level is invalid. Line 1, position 1


That why we use this code:

bool addByteOrderMark = false;
var utf8Encoder = new UTF8Encoding(addByteOrderMark);
var result = utf8Encoder.GetString(stream.ToArray());


Deserialize xml string into object

Let's begin with the xml string we serialized:



var xmlstring = "<?xml version=\"1.0\" encoding=\"utf-8\"?><myobject xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/ConsoleApplication1\"><nr>97</ nr ><status>complete</status></myobject >";


Now we can easily deserialize this into an object:

MyObject myObject;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlstring)))
{
   var serializer = new DataContractSerializer(typeof (MyObject));
    myObject = (MyObject) serializer.ReadObject(ms);
}


Deserialize xml string into XDocument

Last thing I want to do is serialize an xml string into an XDocument, which we can query with Linq.

Let's start again with the xml string we serialized:

var xmlstring = "<?xml version=\"1.0\" encoding=\"utf-8\"?><myobject xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/ConsoleApplication1\"><nr>97</ nr ><status>complete</status></myobject >";

It's also pretty straightforward to deserialize this into an XDocument:


XDocument xDocument;

using (var ms = new MemoryStream(new UTF8Encoding(false).GetBytes(xmlString)))
{
   using (var reader = new XmlTextReader(ms))
   {
      xDocument = XDocument.Load(reader);
   }
}


And there you have your XDocument.

Geen opmerkingen:

Een reactie posten