Json用Interface作为属性反序列化复杂对象

本文关键字:反序列化 复杂 对象 属性 Interface Json | 更新日期: 2023-09-27 18:09:36

我们正在使用。net 4.6构建一个Web Api应用程序我们正在尝试json转换。反序列化对象:复杂对象。该对象有一个复杂对象列表,该对象中有一个接口。我们有一个任务类有一个TaskDetails列表这个类有一个IBehavior

属性
public class Task
{
    public int Id { get; set; }
    public int TaskTypeId { get; set; }  //TYPE
    public List<TaskDetail> TaskDetails { get; set; }
}
public class TaskDetail
{
    public int Id { get; set; }
    public IBehavior Behavior { get; set; }
}

IBehavior是一个空接口…

public interface  IBehavior
{
}

和具体行为是…

public class PartPick : IBehavior
{
    public bool AllowMultiplePicks { get; set; }
    public bool RunLightsOnly { get; set; }
    public bool StandardLightMode { get; set; }
}

public class TorqueTool : IBehavior
{
    public short PSet { get; set; }  
    public short RundownsRequired { get; set; }
    public int MultiSpindleMask { get; set; }
}

JSon有效负载是:

{
    "id": 10000,
    "name": "Attach Spoiler",
    "taskTypeId": 1,
    "behavior": {
        "pSet": 1,
        "rundownsRequired": 1,
        "multiSpindleMask": 4,
        "multiSpindleMaskString": "0010000000000000"
    }
}

我得到以下错误:

" request is invalid.","modelState":{"task.taskDetails[0].behavior. "pSet":["无法创建Bl.Models.EPA.IBehavior类型的实例。类型是接口或抽象类,不能实例化。路径的taskDetails [0] .behavior.pSet '

我尝试创建一个JsonBodyModelbinder: IModelBinder其中反序列化的方法为:

private static T DeserializeObjectFromJson(string json)
{
    var binder = new TypeNameSerializationBinder("");
    var obj = JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto,
        Binder = binder
    });
    return obj;
}

,它被连接在httpConfiguration中:

 config.Services.Insert(typeof(ModelBinderProvider), 0,
            new SimpleModelBinderProvider(typeof(IBehavior), new JsonBodyModelBinder<IBehavior>()));

我也试过把下面的属性放在TaskDetail的IBehavior属性上。

[JsonConverter(typeof(JsonBodyModelBinder<IBehavior>))]
public IBehavior Behavior { get; set; }

Json用Interface作为属性反序列化复杂对象

也许这个答案适合你。基本上,他们提出的是传递实现这个IBehavior接口的类的实例。

public class TaskDetail
{
    public TaskDetail(TorqueTool behavior){
       Behavior = behavior;
    }
    public int Id { get; set; }
    public IBehavior Behavior { get; set; }
}

如果你正在使用DataContractSerializer,你应该使用"KnownTypes"属性来定义你希望实现该接口的类型。

如果您正在使用XML序列化器,则需要为每个类型标记"XmlInclude"属性,如本问题所示。

事实证明,我可以将TaskDetail中的属性从IBehavior更改为dynamic,并且它有效。然后,当我需要使用混凝土类型时,我有一个可以返回混凝土类型的工厂(即torqueTool)。此时我可以输入

JsonConvert.DeserializeObject<TorqueTool>(taskDetail.Behavior.ToString());

我相信反序列化器不知道将接口映射到什么,所以提供一些反序列化器的提示将会起到作用。

public class TaskDetail
{
    TaskDetails(PartPick partPick)
    {
        Behavior = partPick;
    }
    TaskDetails(TorqueTool torqueTool)
    {
        Behavior = torqueTool;
    }
    public int Id { get; set; }
    public IBehavior Behavior { get; set; }
}