1

When I serialize my Page object, Json.Net is not adding the $type property to my Controls (which are in an IList) when it serializes them. I have tried adding the following code to my class constructor and to my WebAPI Startup, but Json.Net is still not adding the $type information to the Control it serializes.

        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All,
            MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
        };

For testing purposes, I added the $type property to the Control myself in the JSON code, and Json.Net was able to deserialize the object correctly, but it is still not serializing correctly. Here's how my classes are setup.

public class Page {
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    public IList<Control> Controls { get; set; }
}

And here is the Control class:

public class Control : ControlBase
{
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.Base; } }
}

And here is the ControlBase abstract class:

public abstract class ControlBase
{
    public Guid Id { get; set; }

    public virtual Enums.CsControlType CsControlType { get; }

    public Enums.ControlType Type { get; set; }

    public string PropertyName { get; set; }

    public IList<int> Width { get; set; }

    public string FriendlyName { get; set; }

    public string Description { get; set; }
}

And here is the OptionsControl which is derived from Control:

public class OptionsControl : Control
{
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.OptionsControl; } }

    public IDictionary<string, string> Options;
}

And this is how the JSON comes out:

"Pages": [
    {
      "Id": "00000000-0000-0000-0000-000000000000",
      "CustomerId": "00000000-0000-0000-0000-000000000000",
      "Controls": [
        {
          "Options": {
            "TN": "TN"
          },
          "CsControlType": 4,
          "Id": "00000000-0000-0000-0000-000000000000",
          "Type": 4,
          "PropertyName": "addresses[0].state",
          "Width": [
            2,
            2,
            6
          ],
          "FriendlyName": "State",
          "Description": null
        }
      ]
    }
]

As you can see, Json.Net did not add the $type property to the JSON object. The problem is that sometimes I need Json.Net to give me a base Control object but sometimes I need it to give me an instance of the OptionsControl object (which inherits from Control). Why is Json.Net not adding the $type property to my Controls?

Targaryen
  • 1,081
  • 2
  • 17
  • 30
  • I might be confused, `"Type": 4,` differs from what you call `$type` how and where is that `$type` that you reference? Can you add the "desired" output to make it more obvious? I might just be not looking at the same thing... – Mark Schultheiss Apr 14 '17 at 17:50
  • Your code works fine for standalone serialization, see https://dotnetfiddle.net/gKetpA. Therefore you must be using some framework such as web api to serialize. What framework are you using? For instance for MVC 4 Web API see [How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API?](https://stackoverflow.com/q/13274625/3744182). Alternatively you could add `[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]` to your list property. – dbc Apr 14 '17 at 17:51
  • @dbc I am using .NET Core WebAPI. My question has been updated with that code. I tried adding `[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]` to the List and I got the `$type` for the Generic List, but not for the Controls within the List. – Targaryen Apr 14 '17 at 17:53
  • 1
    1) It looks like you're using the setting during *deserialization*. That's not going to help. Suggest providing a full [mcve]. 2) Is `[JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)] public IList Controls { get; set; }` what you want? See https://dotnetfiddle.net/zCLbeF – dbc Apr 14 '17 at 17:59
  • @dbc You were right. This code `[JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)] public IList Controls { get; set; }` resolved the issue. Post your answer and I will accept it. – Targaryen Apr 14 '17 at 18:09
  • 1
    My problem was I tried to use `TypeNameHandling =` on the List instead of `ItemTypeNameHandling =`. – Targaryen Apr 14 '17 at 18:13

1 Answers1

1

Rather than modifying the global settings used by your framework, you can add [JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)] to your public IList<Control> Controls { get; set; } property to force type information to be emitted for each item in the list:

public class Page
{
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    [JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)]
    public IList<Control> Controls { get; set; }
}

Sample fiddle.

You might consider sanitizing the type information using a custom serialization binder for reasons explained here.

dbc
  • 104,963
  • 20
  • 228
  • 340