Serializing and deserializing inherited types with Json, anything you want

In my previouos post I’ve created a very simple, home made class to serialize / deserialize an object without needing to know it’s real type, so you can take really advantage of polymorphism.

But if you want a much powerfull solution that also enables you to deserialize lists and complex object graphs, I strongly recommend you the excellent NewtonSoft Json.

Get it with NuGet: Install-Package Newtonsoft.Json

If you really think about it why don’t serialize in JSON? It’s a really simple, powerful, light format and has the advantage that you can also explose it and read it from Javascript if you want without any conversion. Here are a few good reasons to use Json over Xml

So here’s the code, using the library.

Test Model

Here’s the test Model. I’ts pretty lame, I know…


public class Resource
{
    public string ResourceProperty { get; set; }
}

public class Video : Resource
{
   public string VideoProperty { get; set; }
}

First sample. Base class

Just serialize and deserialize an object, no big deal

// Deserialize and deserialize, no big deal
[TestMethod]
public void BaseClassTest()
{
   var resource = new Resource() { ResourceProperty = "Hola" };

   var resourceJSon = JsonConvert.SerializeObject(resource);
   var deserializedJson = JsonConvert.DeserializeObject(resourceJSon);

   Assert.AreEqual(deserializedJson.ResourceProperty, resource.ResourceProperty);
}

Second sample. Inherited class

Here’s the cool stuff:

// Here is the cool stuff. Serialize a derived class, and deserialize as the base class
// without loosing information
 [TestMethod]
 public void InheritedClassTest()
 {
    var video = new Video() { ResourceProperty = "Hola", VideoProperty="Video" };

    // Here is the trick!!
    // We tell the serializer to save the real type for each class
    var settings = new JsonSerializerSettings()
    {
       TypeNameHandling = TypeNameHandling.Objects
    };
    var resourceJSon = JsonConvert.SerializeObject(video, settings);

    // We must deserialize with the same settings
    var deserializedJson = JsonConvert.DeserializeObject<Resource>(resourceJSon, settings);

    Assert.AreEqual(deserializedJson.ResourceProperty, video.ResourceProperty);
    // We can cast to video with no problem
    var castedVideo = deserializedJson as Video;
    Assert.AreEqual(castedVideo.VideoProperty, video.VideoProperty);
    // sorry no polymorphism in this sample :P
 }

Internally what the serializer actually does when using the TypeNameHandling.Objects is to save the type of the object you are serializing,so it can “infer” the type when deserialazing. Just as I did in my previous article. (I swear that I didn’t copy this!!) :P

Third sample. List with base and derived class

And here’s the really cool stuff. You can also serialize a list and deserialize it without needing to know the real type of each element.

 // And this is really cool stuff
 // You can serialize for example a list
 [TestMethod]
 public void List_Test()
 {
    var resource = new Resource() { ResourceProperty = "Resource" };
    var video = new Video() { ResourceProperty = "Video", VideoProperty = "VideoMP4" };

   var list = new List<Resource>() { resource, video };

   // Again the important part are the settings
   var settings = new JsonSerializerSettings()
   {
      TypeNameHandling = TypeNameHandling.Objects
   };

   var serializedList = JsonConvert.SerializeObject(list, settings);

   var deserializedList = JsonConvert.DeserializeObject<List<Resource>> (serializedList, settings);

   // And we recover the information with NO data loss
   Assert.AreEqual("Resource", deserializedList[0].ResourceProperty);
   Assert.AreEqual("VideoMP4", ((Video)deserializedList[1]).VideoProperty);
}

2 thoughts on “Serializing and deserializing inherited types with Json, anything you want

  1. Hans Hinnekint

    Hi, this works nice in the same applicatio, but when transferring this encoded object to another process, the decoding throws an exception, as the application name seems to be embedded in the serialised string, and this differs between the 2 applications ;-(

    Reply
    1. christianarg Post author

      Yes. As I tried to explain in the article “internally what the serializer actually does when using the TypeNameHandling.Objects is to save the type of the object you are serializing,so it can “infer” the type when deserializing.”

      So let’s say you have App A and App B. If you serialize an object with TypeNameHandling.Objects in App A you will need to have the same class in the same namespace in App B to be able to deserialize it . This object is becoming a contract beetween the 2 applications. If you remove the TypeNameHandling.Objects setting it should work, but in that case you won’t have the “benefit” of lossless deserialization of derived clases.

      If you need this benefit, con can:
      – Extract a .dll with all the objects that act like a contract and reference it from App A and App B.
      – Or you can copy & paste this clases with the exact same namespace. Ugly but can work if you have very few clases to send over the wire.

      Reply

Leave a reply to christianarg Cancel reply