1

I made a simple custom JsonConvert class. Right now I'm trying to convert the JSON data to a custom class like so:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    //JObject jo = JObject.Load(reader);
    MyItem instance = serializer.Deserialize<MyItem>(reader);

    // want to do more thing here...
}

Every time it executes the Deserialize<>() method it re-enters the ReadJson method and thus keeping me in a never ending loop.

How can I convert the JSON data to my custom object without ending up in a never ending loop?


Updated

The JSON I'm receiving is generic. I need the custom converter to map it to the right type. The JSON looks like this:

{
    /* Base obj properties, should be mapped to Page.cs */
    "$type": "App.Models.Page, App",
    "title": "Page title",
    "technicalName": "some_key",
    "fields": [

        /* Should be mapped to InputField.cs */
        {
            "$type": "App.Models.InputField, App",
            "type": "input",
            "typeTitle": "Input",
            "title": "Input",
            "technicalName": "input",
            "inputType": "text",
            "defaultValue": "Input default value"
        },

        /* Should be mapped to TextareaField.cs */
        {
            "$type": "App.Models.TextareaField, App",
            "type": "textarea",
            "typeTitle": "Textarea",
            "title": "Textarea",
            "technicalName": "textarea",
            "defaultValue": "default textarea value"
        }
    ]
}

In short my class files look like this:

class Page
{
    public string Title {get;set;}
    public string TechnicalName {get;set;}

    public List<Field> Fields {get;set;} // Note the base class "Field"
}

class InputField : Field // Field has base properties
{
 // InputField has its own properties
}

class TextareaField : Field // Field has base properties
{
 // TextareaField has its own properties
}

TypeNameHandling

I've set the json formatters settings:

jsonOutputFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
jsonInputFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

When I output a Page object through Web API then I get a JSON structure exactly like the one above. When I sent back that exact JSON data I expect it to nicely map back to a Page object with the correct types in the Field list property.

But all the Fields are mapped to its base class Field instead of the types that are defined in $type.

So currently the JSON formatter works great for outputting. It shows all the $types. But the input mapping isn't really mapping back to its specific types.

Vivendi
  • 20,047
  • 25
  • 121
  • 196
  • Why did you create a custom `JsonConvert` in the first place? Why not use the one provided by the library? – Yuval Itzchakov May 25 '15 at 11:45
  • @YuvalItzchakov Because I have a page that posts a JSON array which can be of a generic type. I'm eventually going to use the custom converter to map it back to the right type. – Vivendi May 25 '15 at 11:49
  • You can try changing the method signature to `public new object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)` – Jurgen Camilleri May 25 '15 at 11:51
  • @JurgenCamilleri Doesn't work, it's an abstract method that needs to be overridden. – Vivendi May 25 '15 at 11:52
  • @Vivendi Post your JSON structure. – Yuval Itzchakov May 25 '15 at 11:53
  • @YuvalItzchakov Added the JSON – Vivendi May 25 '15 at 12:07
  • Are you serializing with Json.NET as well? – Yuval Itzchakov May 25 '15 at 12:13
  • @YuvalItzchakov The `Web Api` serializes my object. I don't need any custom methods for that. – Vivendi May 25 '15 at 12:15
  • Then read [this](http://stackoverflow.com/questions/6348215/how-to-deserialize-json-into-ienumerablebasetype-with-newtonsoft-json-net) answer. – Yuval Itzchakov May 25 '15 at 12:27
  • [This](http://stackoverflow.com/a/8031283/567073) might help – HadiRj May 25 '15 at 12:28
  • @YuvalItzchakov That is exactly what I want to do. Serializing objects gives me the `$type` of each object in JSON. Unfortunately, sending that JSON data back doesn't map its generic objects back to the specified `$type` when its Deserialized by the Web API. – Vivendi May 25 '15 at 13:31
  • Because you need to tell the `JsonFormatter` to use `TypeNameHandling.All` – Yuval Itzchakov May 25 '15 at 13:33
  • @YuvalItzchakov You are right. I was hoping I could get away with `Objects` only, since that makes a cleaner JSON structure. But using `All` will do fine also in my case. Could you please provide this as an answer so I have something to accept. – Vivendi May 25 '15 at 13:53

2 Answers2

1
public static class ConvertToJson
{ 
    public static T Deserialize<T>(string json)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            return (T)serializer.ReadObject(ms);
        }
    }
}
Jurgen Camilleri
  • 3,559
  • 20
  • 45
Gera
  • 149
  • 4
1

Given that you use Json.NET on the Web API side, you don't need a custom JsonConverter. You can explicitly tell the JsonFormatter (which internally uses Json.NET) to use TypeNameHandling.All. That way, it'll know exactly which type to deserialize given an IEnumerable<BaseType>. More on that can be find in how to deserialize JSON into IEnumerable<BaseType> with Newtonsoft JSON.NET

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321