68

I have the following 2 functions:

public static string Serialize(object obj)
{
    DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
    MemoryStream memoryStream = new MemoryStream();
    serializer.WriteObject(memoryStream, obj);
    return Encoding.UTF8.GetString(memoryStream.GetBuffer());
}

public static object Deserialize(string xml, Type toType)
{
    MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
   // memoryStream.Position = 0L;
    XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, Encoding.UTF8, new XmlDictionaryReaderQuotas(), null);
    DataContractSerializer dataContractSerializer = new DataContractSerializer(toType);
    return dataContractSerializer.ReadObject(reader);
}

The first one seems to serialize an object to an xml string just fine. The XML appears valid, no broken tags, no white spaces at the beginning or at the end, etc. Now the second function doesn't want to deserialize my XML string back to the object. On the last line I get:

There was an error deserializing the object of type [MY OBJECT TYPE HERE]. The data at the root level is invalid. Line 1, position 1.

What am I doing wrong? I tried rewriting the Deserialize function a few times, and it always seems to be the same kind of error.

Oh, and this is how I'm calling the 2 functions:

SomeObject so = new SomeObject();
string temp = SerializationManager.Serialize(so);
so = (SomeObject)SerializationManager.Deserialize(temp, typeof(SomeObject));
halfer
  • 19,824
  • 17
  • 99
  • 186
Dimskiy
  • 5,233
  • 13
  • 47
  • 66

4 Answers4

146

Here is how I've always done it:

    public static string Serialize(object obj) {
        using(MemoryStream memoryStream = new MemoryStream())
        using(StreamReader reader = new StreamReader(memoryStream)) {
            DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
            serializer.WriteObject(memoryStream, obj);
            memoryStream.Position = 0;
            return reader.ReadToEnd();
        }
    }

    public static object Deserialize(string xml, Type toType) {
        using(Stream stream = new MemoryStream()) {
            byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
            stream.Write(data, 0, data.Length);
            stream.Position = 0;
            DataContractSerializer deserializer = new DataContractSerializer(toType);
            return deserializer.ReadObject(stream);
        }
    }
Ray Vernagus
  • 6,130
  • 1
  • 24
  • 19
  • 7
    For Deserialize, it might be more efficient to replace the GetBytes/Write with "using (StreamWriter writer = new StreamWriter(stream, encoding) { writer.Write(xml); ... }" to avoid the extra byte[] buffer. – crokusek Jan 10 '13 at 03:51
  • 1
    This is awesome, and still incredibly helpful. Most importantly, this is correct. – Feign Jul 27 '15 at 18:24
  • I've used these methods too, but I got a little problem when serialize-deserialize derived classes of a base class. I had to modify the serialize-method just a bit ([link](https://stackoverflow.com/a/45443874/3785903)) to supply the base class type. – Nick Sick Aug 01 '17 at 17:15
  • This throws CA2202 [https://learn.microsoft.com/en-us/visualstudio/code-quality/ca2202-do-not-dispose-objects-multiple-times?view=vs-2015&redirectedfrom=MSDN ] – Vinod Srivastav Dec 06 '19 at 09:58
42

Other solution is:

public static T Deserialize<T>(string rawXml)
{
    using (XmlReader reader = XmlReader.Create(new StringReader(rawXml)))
    {
        DataContractSerializer formatter0 = 
            new DataContractSerializer(typeof(T));
        return (T)formatter0.ReadObject(reader);
    }
}

One remark: sometimes it happens that raw xml contains e.g.:

<?xml version="1.0" encoding="utf-16"?>

then of course you can't use UTF8 encoding used in other examples..

rudolf_franek
  • 1,795
  • 3
  • 28
  • 41
34

I ended up doing the following and it works.

public static string Serialize(object obj)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
        serializer.WriteObject(memoryStream, obj);
        return Encoding.UTF8.GetString(memoryStream.ToArray());
    }
}

public static object Deserialize(string xml, Type toType)
{
    using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
    {
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, Encoding.UTF8, new XmlDictionaryReaderQuotas(), null);
        DataContractSerializer serializer = new DataContractSerializer(toType);
        return serializer.ReadObject(reader);
    }
}

It seems that the major problem was in the Serialize function when calling stream.GetBuffer(). Calling stream.ToArray() appears to work.

Dimskiy
  • 5,233
  • 13
  • 47
  • 66
  • 1
    GetBuffer() fails, because the buffer of MemoryStream is allocated in 256 byte chunks and all bytes of all chunks even the unused zero bytes after the terminating '\0' of the string are returned by GetBuffer(). That means the resulting string properly has a bunch of tailing zeros. – Doomjunky Jan 12 '16 at 23:25
-2

This best for XML Deserialize

 public static object Deserialize(string xml, Type toType)
    {

        using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
        {
            System.IO.StreamReader str = new System.IO.StreamReader(memoryStream);
            System.Xml.Serialization.XmlSerializer xSerializer = new System.Xml.Serialization.XmlSerializer(toType);
            return xSerializer.Deserialize(str);
        }

    }
  • You could provide some explanation for your suggestion. Please have a look at [How to Answer](http://stackoverflow.com/questions/how-to-answer). – Serge Belov Nov 15 '12 at 01:06