Luiggi
Luiggi

Reputation: 43

JSON Deserialization for polymorphic array in MVC 4 controller

Im using MVC 4 my ActionController recives the following Json:

{
    "MainId": 1,
    "Actions": [
        {
            "Attribute1ClassA": 1,
            "Attribute2ClassA": 2
        },
        {
            "Attribute1ClassB": 3,
            "Attribute2ClassB": 4
        },
        {
            "Attribute1ClassC": 5
        }
    ]
}

and the Controller:

[HttpPost]
public ActionResult Commit(ActionsSummaryViewModel summary)
{
//DO stuff
}

and declaration for classes:

public ActionsSummaryViewModel
{
    public int MainId {get;set;}
    public IList<MainClass> {get;set;}
}

public class MainClass
{
}

public class ClassA : MainClass
{
   public int Attribute1ClassA {get;set;}
   public string Attribute2ClassA {get;set;}
}

public class ClassB : MainClass
{
   public int Attribute1ClassB {get;set;}
   public string Attribute2ClassB {get;set;}
}

public class ClassC : MainClass
{
   public int Attribute1ClassC {get;set;}
}

So now, how can i manage the deserialization for the MainClass when the action controller receive the JSON ? because when i call the action the list items are null.

if part of the solution is Json.NET, how i can implement for MVC 4 controllers?

Thanks for your help.

Upvotes: 1

Views: 1976

Answers (2)

Dmitry Pavlov
Dmitry Pavlov

Reputation: 28290

You could parse JSON into dynamic object instead using Json.NET:

using Newtonsoft.Json.Linq:

dynamic data = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = data.Name;
string address = data.Address.City;

Upvotes: 0

Paul
Paul

Reputation: 6218

You need a property or set of properties from which you can determine which type the class is to use this method. Using JSON.NET, I deserialize the incoming JSON as a dynamic object, then check the common property, determine the type, and deserialize the value again this type using my model type:

// I'm assuming here you've already got your raw JSON stored in 'value'
// In my implementation I'm using the Web API so I use a media formatter,
// but the same principle could be applied to a model binder or however 
// else you want to read the value.

dynamic result = JsonConvert.DeserializeObject(value);
switch ((string)result.type)
{
case "typeone":
return JsonConvert.DeserializeObject<ModelOne>(value);
// ...
default: return null;
}

There's a little bit of extra overhead here because you're deserializing twice, but it's worth it in most cases to me because it's easy to understand what's going on and add new types as needed.

Upvotes: 2

Related Questions