I will preface this by saying that I know what the problem is, I just don't know how to solve it. I am communicating with a .NET SOA data layer that returns data as JSON. One such method returns an object that has several collections within it. The object basically looks like this:

{
  "Name":"foo",
  "widgetCollection":[{"name","foo"}, {"name","foo"},],
  "cogCollection": [{"name","foo"}, {"childCogs",<<new collection>>},],
}

My class that represents this object looks like this:

public class SuperWidget : IWidget
{
    public string Name { get; set; }

    public ICollection<IWidget> WidgetCollection { get; set; }
    public ICollection<ICog> CogCollection { get; set; }

    public SuperWidget()
    {
    }

    [JsonConstructor]
    public SuperWidget(IEnumerable<Widget> widgets, IEnumerable<Cog> cogs)
    {
        WidgetCollection = new Collection<IWidget>();
        CogCollection = new Collection<ICog>();

        foreach (var w in widgets)
        {
            WidgetCollection.Add(w);
        }
        foreach (var c in cogs)
        {
            CogCollection.Add(c);
        }
    }
}

This constructor worked fine until the cogCollection added a child collection, and now I am getting the above error. A concrete cog class looks like this:

[Serializable]
public class Cog : ICog
{
    public string name { get; set; }

    public ICollection<ICog> childCogs { get; set; }        
}  

I don't want to change the collection to a concrete type because I am using IoC. Because I am using IoC I would really like to get away from the need to have the JsonConstructors that take concrete parameters, but I haven't figured out a way to do that. Any advice would be greatly appreciated!

Update:

Yuval Itzchakov's suggestion that this question is probably a duplicate is somewhat true (it seems). In the post referenced, one of the answers down the page provides same solution that was provided here. I didn't notice that answer, since the OP's question was different then the one I had here. My mistake.

-------my solution--------

正如我所说:马特的解决方案需要一点工作,但我得到了一些适合我的设置.他最初的解决方案有一点我不喜欢,就是这样的台词:

 return objectType == typeof(ICog); 

按照这种模式,对于通过网络接收到的每个抽象类型,都需要一个JsonConverter.这在我的情况下并不理想,因此我创建了一个通用JsonConverter:

public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T>
{
    private readonly IUnityContainer Container;
    public GenericJsonConverter(IUnityContainer container)
    {
        Container = container;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader);
        var result = Container.Resolve<T>();
        serializer.Populate(target.CreateReader(), result);
        return result;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

然后在我反序列化数据之前,我做了如下操作:

 var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
 settings.Converters.Add((JsonConverter)Container.Resolve<IBaseJsonConverter<ICog>>());

提示:如果您使用ReSharper,(JsonConverter)将在此场景中给您一个可疑强制转换警告.

Hopefully someone else finds this useful down the road!

推荐答案

您需要向Json.Net提供自定义序列化程序,以告诉它如何处理子齿轮.例如:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new CogConverter());

Your CogConverter will need to inherit from JsonConverter and specify that it CanConvert your ICog interface. Perhaps something along the lines of:

public class CogConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ICog);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, typeof(Cog));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

如果是这样的话,我建议您在IoC容器中注册JsonSerializerSettings.如果序列化程序不能负责实际构建Cog本身,则可能需要考虑对容器进行CogConverter次访问;这一切都取决于您的特定架构.

Edit

Upon further reading, it seems like you might be looking for specifically how to use the IoC created ICog for population. I'm using the following as part of my ReadJson:

var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader);
var objectType = DetermineConcreteType(target);
var result = iocContainer.Resolve(objectType);
serializer.Populate(target.CreateReader(), result);
return result;

这允许您使用任何对象,并从原始JSON填充它,在DetermineConcreteType方法中使用自定义类型.

Json相关问答推荐

最新版本的Deneb在数据溢出时不支持滚动

JSON:将项';S键/名称移动到属性中,并使用JQ将其转换为数组

在Golang中从 struct 手动创建JSON对象

在MongoDB中检索某个月份和年份的JSON文档

Postgres Select json数组并重新映射属性名称

给定一个包含两个数组的JSON输入文件,如何使用Jolt将一个数组中的每个元素与另一个数组组合在一起?

如何从一个700MB的json文件中列出PowerShell中的所有密钥?

将JSON数组组织到菜单中

在 json 对象中存储多个键:值对

如何在 jq 中按 IP 地址排序?

在 NX 工作区中跨多个应用共享 ngx-translate 翻译文件

jq可以在两个JSON对象列表中依次添加对象吗?

将 colly 包输出文本添加到 golang 中的映射

谷歌浏览器不允许我放置断点

通过 JSON 发送 HTML 代码

如何让 javascript 从 .json 文件中读取?

带有 Jackson 的不可变 Lombok 注释类

SCRIPT5009:JSON未定义

如果键可能不存在,则从 Python dict 读取

如何遍历 JSON 中的条目?