28

Sometimes I want to emulate stored data of my classes without setting up a round trip to the database. For example, let's say I have the following classes:

public class ShoppingCart
{
    public List<CartItem> Items {get; set;}
    public int UserID { get; set; }
}

public class CartItem
{
    public int SkuID { get; set; }
    public int Quantity  { get; set; }
    public double ExtendedCost  { get; set; }
}

Let's say I build a ShoppingCart object in memory and want to "save" it as an XML document. Is this possible via some kind of XDocument.CreateFromPOCO(shoppingCart) method? How about in the other direction: is there a built-in way to create a ShoppingCart object from an XML document like new ShoppingCart(xDoc)?

pnuts
  • 58,317
  • 11
  • 87
  • 139
Ben McCormack
  • 32,086
  • 48
  • 148
  • 223

4 Answers4

61

XmlSerializer is one way to do it. DataContractSerializer is another. Example with XmlSerializer:

using System.Xml;
using System.Xml.Serialization;

//...

ShoppingCart shoppingCart = FetchShoppingCartFromSomewhere();
var serializer = new XmlSerializer(shoppingCart.GetType());
using (var writer = XmlWriter.Create("shoppingcart.xml"))
{
    serializer.Serialize(writer, shoppingCart);
}

and to deserialize it back:

var serializer = new XmlSerializer(typeof(ShoppingCart));
using (var reader = XmlReader.Create("shoppingcart.xml"))
{
    var shoppingCart = (ShoppingCart)serializer.Deserialize(reader);
}

Also for better encapsulation I would recommend you using properties instead of fields in your CartItem class.

Bartho Bernsmann
  • 2,393
  • 1
  • 25
  • 34
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
13

Nicely done. Here is the example to serialize plain POCO to string.

    private string poco2Xml(object obj)
    {
        XmlSerializer serializer = new XmlSerializer(obj.GetType());
        StringBuilder result = new StringBuilder();
        using (var writer = XmlWriter.Create(result))
        {
            serializer.Serialize(writer, obj);
        }
        return result.ToString();
    }
Jeson Martajaya
  • 6,996
  • 7
  • 54
  • 56
3

You could serialize/deserialize with either the XmlSerializer or the DataContractSerializer.

Annotate your classes with DataContract and DataMember attributes and write something like this to serialize to xml to a file.

ShoppingCart cart = ...
using(FileStream writer = new FileStream(fileName, FileMode.Create))
{
   DataContractSerializer ser = new DataContractSerializer(typeof(ShoppingCart));
   ser.WriteObject(writer, cart);
}
Mikael Svenson
  • 39,181
  • 7
  • 73
  • 79
  • What if an exception is thrown during the serialization? – Darin Dimitrov Jul 28 '10 at 20:12
  • 1
    @Darin: Which you will often encounter when starting to use the DataContractSerializer. But it usually boils down to attribute annotation of your classes. The XmlSerializer is easier to use as it takes almost whatever you throw at it, but the DataContractSerializer is faster, but requires more "work" to get it up and running. – Mikael Svenson Jul 28 '10 at 20:26
  • @Mikael, I think you didn't get my point. What I meant was that if an exception is thrown you will leak a file handle which is very bad as it will lock the file and no other process be able to do anything with it until you kill the application. – Darin Dimitrov Jul 28 '10 at 20:28
  • @Darin: edited in that just now, and I need to improve at writing production code quality in code samples, not just solve the issue. – Mikael Svenson Jul 28 '10 at 20:30
  • 2
    @Mikael, StackOverflow is a quite well referenced site meaning that what you write here could potentially be seen and irresponsibly used by many people in production code and I think that basic things like disposing disposable resources is a minimum to avoid promoting bad practices. I am sure that there are many people that simply do a copy-paste from blog posts without even realizing the catastrophic implications this might have on their production systems. – Darin Dimitrov Jul 28 '10 at 20:36
  • 1
    @Darin: Very true indeed. I actually copy/pasted my code from MSDN and modified it, so they have work to do as well in their samples. Except the sample is a console app, so any file lock will be dealt with upon the program "crashing". – Mikael Svenson Jul 28 '10 at 20:56
  • Just tested out XmlSerializer on a simple POCO class just to have it throw up on me an error that the POCO does not have a parameterless constructor. Here be dragons. – Tore Aurstad Nov 12 '18 at 18:21
  • @ToreAurstad annotate the poco https://learn.microsoft.com/en-us/dotnet/standard/serialization/controlling-xml-serialization-using-attributes and harness the dragons :) – Mikael Svenson Nov 13 '18 at 13:30
0

Just mark up what you want to serialize with [XmlElement(name)] (or XmlAttribute, XmlRoot, etc) and then use the XmlSerializer. If you need really custom formating, implement IXmlSerializable.

AllenG
  • 8,112
  • 29
  • 40