Click here to Skip to main content
15,891,607 members
Articles / Programming Languages / C#
Tip/Trick

Serialize and Deserialize Classes with Interface Properties with JSON.NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
5 Sep 2016CPOL2 min read 50.7K   5   3
Serialize concrete classes that have interface properties

Introduction

If you have to deserialize a JSON stream into a concrete class that has interface properties, Json.NET helps you to serialize the object adding a $type property to the JSON, which allows him to know which concrete type it needs to deserialize the object into.

Using the Code

I have been facing the same problem these days, and I came to this easy, fast and readable solution:

Let's say that we use Json.NET to serialize/deserialize objects sent-to/received-from a Web Service, and we want to serialize/deserialize classes that have interface properties.

Serializing will give us no issues (using the standard settings), but when we will try to deserialize the model, we will get the following error:

Quote:

Could not create an instance of type Namespace.Intarface. Type is an interface or abstract class and cannot be instantiated.

  • Serializing a class that implements an interface is simple.
  • Deserializing JSON to one of many possible classes that implement an interface is not.
  • Json.NET allows us to solve this problem by simply adding an extra settings during the serialization process.

We just need to add an extra setting during the serialization:

JavaScript
var indented = Formatting.Indented;
var settings = new JsonSerializerSettings()
{
      TypeNameHandling = TypeNameHandling.All
};
string serialized = JsonConvert.SerializeObject(wizardConf, indented, settings);

And then apply the same setting during the deserialization:

JavaScript
var settings = new JsonSerializerSettings()
{
      TypeNameHandling = TypeNameHandling.All
};
YourObject obj =  JsonConvert.DeserializeObject<yourobject>(JsonString, settings);

So, let's say we got to serialize an object containing two list of Interfaces:

JavaScript
public class Class1 : IInterface1
{
   public void method1()
   {
       // whatever1
   }
}
 
public class Class2 : IInterface2
{
   public void method2()
   {
       // whatever2
   }
}
 
   public class ObjToSerialize
   {
       public List<IInterface1> list1;
       public List<IInterface2> list2;
 
       public ObjToSerialize()
       {
           list1 = new List<IInterface1>();
           list2 = new List<IInterface2>();
       }
   }

And at runtime, we added one object to each list:

JavaScript
ObjToSerialize obj = new ObjToSerialize();
obj.list1.Add(new Class1());
obj.list2.Add(new Class2());

By adding the TypeNameHandling flag, the serialized class will appear as follows:

JavaScript
{
  "$type": "Namespace.ObjToSerialize, AssemblyName",
  "list1": {
    "$type": "System.Collections.Generic.List`1[[Namespace.IInterface1, AssemblyName]], mscorlib",
    "$values": [
      {
        "$type": "Namespace.Class1, AssemblyName"
      }
    ]
  },
  "list2": {
    "$type": "System.Collections.Generic.List`1[[Namespace.IInterface2, AssemblyName]], mscorlib",
    "$values": [
      {
        "$type": "Namespace.Class2, AssemblyName"
      }
    ]
  }
}

The resulting JSON file basically tells everything we need to know.
It says that the ObjToSerialize contains two properties, each of them is a List of Interfaces, whose implementation is Class1 in the first case and Class2 in the second case.

The deserializer will take this string and easily reconstruct the object as it has all the details of the interface implementation.

Quote:

The TypeNameHandling flag adds a $type property to the JSON.

The $type is a fully-qualified type which allows Json.NET to know which concrete type it needs to deserialize the object into. This allows you to deserialize an object while still fulfilling an interface or abstract base class.

The downside, however, is that this is very Json.NET-specific.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Ireland Ireland
Summary
I am an Informatics Engineer with a University Degree in Informatics Engineering and a PhD in Information Engineering.
I have more than 9 years of working experience ICT (from Development to Team Leader) with and In-depth technical / IT know-how.
Practical competences in development, analysis and project management in terms of coordination and content.

Keywords / Skill Set
C# 7.0, NET Core, ASP NET Core, EF Core; HTML(5), CSS(3), Typescript, JavaScript, jQuery,Telerik Kendo, AngularJS, SignalR; MVC, MVVM; SQL, T-SQL, Sql Server; Azure cloud based services, Amazon Web Services
Relevant Web Applications / Tools:
Visual Studio 2017, SQL Server 2016; TFS, Git

Languages: Italian (mother tongue), English (fluent).

Education:

1998 – 2004, University Of Siena (IT), Tuscany

BSc in Informatics Engineering

2004 – 2007, Superior School of Doctorate, University of Siena (IT), Tuscany

PhD in Information Engineering

Comments and Discussions

 
QuestionWhat happens in a heterogenous environment? Pin
Klaus Luedenscheidt5-Sep-16 18:41
Klaus Luedenscheidt5-Sep-16 18:41 
AnswerRe: What happens in a heterogenous environment? Pin
Jono Stewart5-Sep-16 20:37
Jono Stewart5-Sep-16 20:37 
AnswerRe: What happens in a heterogenous environment? Pin
Aless Alessio6-Sep-16 3:33
Aless Alessio6-Sep-16 3:33 
Thanks for your question.

Sorry, I wasn't probably clear enough, so I will update the Tip&Trick Introduction in order to underline the following concepts:

In this example I am expressly talking about a C# client using JSON.NET to serialize/deserialize concrete classes with Interface Properties.

DTO/DataContracts are flat and cross platform, and are the best option to choose when passing data from the client to server (and viceversa). However, when designing them, you must define members/properties in them that are concrete (therefore, interface properties does not apply)


Where did I use this Tip&Trick?

My Front-End application has a wizard which allows the user to configure a certain number of attributes within the system. At the end of the wizard, the configuration is then "saved" into a concrete class which stays in memory until necessary. However, the user can save this configuration at anytime. And when he does, the configuration is simply serialized and sent to the Web Service, which just takes the string and saves it in the DB (without deserializing it).

The deserialization process happens client-side as well. User asks to load a certain configuration and so it asks to WebService to give it back to him. The WebService simply reads the string from the Database and sends it back to the client, who reconstructs the Configuration by deserializing it.

In my case, the Configuration class contains a series of Interface members, and then I needed a fast and bullet-proof way to serialize and deserialize it. Since, it is a WPF application, i am writing in C# and using JSON.Net.

This Tip&Trick does not really apply to a Java application, since in that case i would use gson from google, which probably has a different way of handling type names.

Anyway, thanks for taking time to read the article and show your interest, i appreciate. Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.