[英]Json.Net deserialize into C# derived class
Json.Net 不会将接收到的对象反序列化为Control类的适当派生类。 (请参阅下面对问题的解释。另外请注意,我认为这是解释问题所需的最少代码量。感谢您提前审查此问题。)
我正在尝试将以下类序列化/反序列化为JSON。
public class Page {
public Guid Id { get; set; }
public Guid CustomerId { get; set; }
public IList<Control> Controls { get; set; }
}
这是Control类:
public class Control : ControlBase
{
public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.Base; } }
}
这是ControlBase抽象类:
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; }
}
这是从Control派生的OptionsControl:
public class OptionsControl : Control
{
public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.OptionsControl; } }
public IDictionary<string, string> Options;
}
将OptionsControl序列化后,JSON如下所示。 请注意,Json.Net添加了$type
属性,因此(据说)它可以将控件反序列化为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"
}
但是,当我尝试反序列化Page(包含基本Controls和OptionsControls)时,所有控件都反序列化到基本Control中,而options
属性(包括上面的状态列表)被忽略。
这是我尝试反序列化(和更新)通过WebAPI服务收到的Page对象的方式:
[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
};
}
}
如您所见,我使用TypeNameHandling.All(如文档中所述,并在SO上多次提到)进行反序列化(就像我在序列化期间一样,这就是在JSON中生成$type
属性的方式)。 但是,当我反序列化Page对象时,Page对象中的所有OptionsControl
反序列化为常规的基本Control
,因此会忽略Options
属性(因此不会更新/丢弃我的状态列表)。
我如何获得Json.Net来适当地反序列化控件及其衍生版本?
看来问题可能是由于$type
元数据属性不是控件的JSON中的第一个属性这一事实造成的。 通常,Json.Net需要将此属性设置为第一个才能识别它。 尝试添加
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
反序列化时将其设置为您的设置。 这应该允许Json.Net稍后在JSON中找到$type
属性。
我认为您应该在Web-api启动类中设置配置。
尝试在startup.cs文件中输入类似
GlobalConfiguration.Configuration.Formatters.Clear(); // or remove just the json one
var jsonformatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter()
{
SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
// all your configurations
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All
}
};
GlobalConfiguration.Configuration.Formatters.Add(jsonformatter);
我认为您正在丢失信息,因为在该方法中获得了反序列化的Object项(页面),然后通过调用page.tostring()方法再次对其进行序列化,然后使用序列化程序属性对其进行反序列化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.