【问题标题】:Json.Net deserialize into C# derived classJson.Net 反序列化为 C# 派生类
【发布时间】:2017-04-14 14:19:19
【问题描述】:

Json.Net not 将它接收到的对象反序列化为我的 Control 类的正确派生类。 (请参阅以下问题说明。另外请注意,我认为这是解释问题所需的最少代码量。提前感谢您查看此问题。)

我正在尝试将以下类序列化/反序列化为 JSON。

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

这里是控制类:

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"
              }

但是,当我尝试反序列化页面(包含基本控件和选项控件)时,所有控件都被反序列化为基本控件,并且 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)。但是,当我反序列化 Page 对象时,Page 对象中的任何 OptionsControls 都会被反序列化为常规基础 Controls,因此 Options 属性将被忽略(因此我的状态列表不会更新/丢弃) .

如何让 Json.Net 正确反序列化我的控件及其派生类?

【问题讨论】:

    标签: c# json serialization asp.net-web-api json.net


    【解决方案1】:

    看起来问题可能是由于$type 元数据属性不是您的控件的 JSON 中的第一个属性。通常,Json.Net 需要将此属性放在首位才能识别它。尝试添加

    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
    

    反序列化时的设置。这应该允许 Json.Net 稍后在 JSON 中找到 $type 属性。

    【讨论】:

    • 是的,经过很多小时,这也是我的解决方案。但是,我首先必须弄清楚 where 来设置值。你的答案与这个答案相结合是我的救援:stackoverflow.com/a/13274791/3812472
    【解决方案2】:

    我认为你应该在你的 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);
    

    我认为您正在丢失信息,因为您在方法中获得了一个反序列化的对象项(页面),然后您通过调用 page.tostring() 方法再次对其进行序列化,然后使用您的序列化程序属性再次对其进行反序列化。

    【讨论】:

      猜你喜欢
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      相关资源
      最近更新 更多