XML-Serialisierung von Objekten mit Hilfe von WCF-Klassen
Wer schon einmal vor der Aufgabe stand, den Zustand seiner Objekt in eine XML Datei zu serialisieren weiß das .NET hierfür den Namespace System.Xml.Serialization und im speziellen die Klasse XmlSerializer vorsieht. Jeder der diese Klasse zum Serialisieren oder Deserialisieren schon benutzt hat wird festgestellt haben das nur öffentliche Member der zu serialisierenden Objekte in die XML Datei geschrieben werden. Alle anderen Member werden leider nicht berücksichtigt. Um diese nun doch noch serialisieren zu können, kann man public Properties einführen. Dies ist aber oftmals nicht erwünscht, da andere Klassen diese Member erst gar nicht kennen sollen geschweige denn darauf zugreifen dürfen.
Für dieses Problem liefert WCF (ab dem .NET Framework 3.0) nun Abhilfe. Der Schlüssel zum Ziel hierfür ist die Klasse DataContractSerializer im Namespace System.Runtime.Serialization. Primär dient diese Klasse zur Serialisierung/Deserialisierung von Objekten die mittels WCF z.B. über das Netzwerk verschickt oder empfangen werden. Man kann die Klasse aber auch hervorragend zur Serialisierung seiner eigenen Objekte verwenden und sehr einfach XML-Code aus seinen Objekten erzeugen.
Dies kann z.B. sehr nützlich für Configdateien sein. Es gibt gegenüber dem XmlSerializer mehrere Vorteile. Zum einen ist es möglich jegliche Member, also auch private und protected Member, zu serialisieren. Zum anderen ist der DataContractSerializer 10%-20% schneller wie der XML-Serializer, siehe dazu auch den Vergleichstest.
Ein wichtiger Unterschied besteht darin das der DataContractSerializer nach dem Opt-in Verfahren arbeitet und nicht nach dem Opt-out Verfahren wie der XmlSerializer. Das bedeutet man muss explizit angeben welches Member serialisiert werden soll. Dies geschieht mittels Attributen. Eine genauere Übersicht über die Unterschiede der beiden Serializer und ausführlichere Beispiele findet sich hier. Ein kurzes Beispiel zeigt im folgenden die Verwendung des DataContractSerializer.
Als erstes müssen in der Klasse des zu serialiserenden Objektes einige Attribute angegeben werden. So muss die Klasse generell als Serialisierbar markiert werden mit dem Attribut [DataContract]. Danach müssen die Member die serialisiert werden sollen mit dem Attribut [DataMember] versehen werden. Optional können hier unter anderem noch der Name und die Reihenfolge angegeben werden die im XML Dokument verwendet werden soll.
namespace TestNamespace { [DataContract] public class Student { [DataMember (Order=0, Name="LastName")] public string Name; [DataMember (Order=0)] private int Age = 25; } }
Im Folgenden wird dann einfach ein Objekt der eben definierten Klasse erstellt, initialisiert und mit Hilfe des DataContractSerializers in die Datei Student.xml serialisiert. Anschließend wird die gleiche Datei wieder in ein zweites, neues Objekt deserialisiert.
Student student = new Student { Name = "Tom"}; DataContractSerializer ds = new DataContractSerializer (typeof (Student)); using (Stream s = File.Create (@"C:\Student.xml")) ds.WriteObject (s, student); // Serialize Student student2; using (Stream s = File.OpenRead (@"C:\Student.xml")) student2 = (Student) ds.ReadObject (s); // Deserialize
Das erzeugte XML-Dokument sieht dann folgendermaßen aus:
<Student xmlns="<http://schemas.datacontract.org/2004/07/TestNamespace>" xmlns:i="<http://www.w3.org/2001/XMLSchema-instance>"> <Age>25</Age> <LastName>Tom</LastName> </Student>
Man sieht die Verwendung des DataContractSerializers ist denkbar einfach. Es gibt noch ein paar Kniffe und Tricks mit denen man auch Enums und andere Typen Serialiseren kann, so wie die Formatierung des XML etwas steuern kann. Eine hilfreiche Zusammenfassung findet sich dazu noch hier.