Json.Net is not deserializing the object it receives into the proper derivatives of my Control class. (Please see the following explanation of the problem. Also please note, I feel this is the minimum amount of code required to explain the issue. Thanks ahead of time for reviewing this problem.)
I am trying to serialize/deserialize the following class(es) into/from JSON.
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;
}
When the OptionsControl is serialized, the JSON looks like the following. Note that Json.Net adds the $type
property, so that (supposedly) it can deserialize the control back into an OptionsControl.
{
"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,
"$type":"MyApp.Infrastructure.Core.Models.UI.Controls.OptionsControl, MyApp.Infrastructure.Core"
}
However, when I try to deserialize the Page (which contains the base Controls and OptionsControls), all controls are deserialized into the base Control and the options
property (which includes the list of States, above) is ignored.
This is how I try to deserialize (and update) the Page object I receive via a WebAPI service:
[HttpPut]
[ActionName("UpdatePage")]
public async Task<CommandResult> UpdatePageAsync([FromBody]Object page)
{
try
{
// Deserialize the page into the correct object
// When I Debug.WriteLine the page.ToString(), the page still has the $type property at this point (before it is deserialized).
var dsPage = return JsonConvert.DeserializeObject<Page>(page.ToString(), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
// The dsPage passed in here does not have any OptionsControls.
// At this point, they have all been deserialized into the base Control, unfortunately.
return await _uiCommandFacade.UpdatePageAsync(dsPage, msg);
}
catch (Exception ex)
{
return new CommandResult()
{
ErrorType = ErrorType.ControllerError,
DeveloperMessage = $"Unable to update page",
Exception = ex
};
}
}
As you can see, I am using TypeNameHandling.All (as described in the docs and mentioned many times on SO) for the deserialization (just as I am during the serialization, which is what generates the $type
property in the JSON). However, when I deserialize the Page object, any OptionsControl
s in the Page object are deserialized into regular base Control
s, so the Options
property is ignored (and thus my list of States is not updated / thrown away).
How do I get Json.Net to properly deserialize my Controls and its derivatives?