2014-07-09 144 views
17

我将通过说我知道问题是什么,我只是不知道如何解决它。我正在与以JSON形式返回数据的.NET SOA数据层进行通信。一种这样的方法返回一个对象,其中有多个集合。对象基本上是这样的:类型是一个接口或抽象类,不能实例化

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

我的类,它表示这个对象是这样的:

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); 
     } 
    } 
} 

直到cogCollection添加一个子集合这个构造函数工作得很好,现在我得到上述错误。一个具体的COG类看起来是这样的:

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

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

我不想因为我使用的IoC到集合更改为具体类型。因为我正在使用IoC,所以我真的很想避免需要具有具体参数的JsonConstructors,但我还没有想出一种方法来实现这一点。任何建议将不胜感激!

更新:

尤瓦Itzchakov的建议,这个问题可能是一个重复的是有点真(似乎)。在引用的帖子中,页面中的一个答案提供了与此处提供的相同的解决方案。我没有注意到答案,因为OP的问题与我在这里的问题不同。我的错。

-------我的解决方案--------

正如我所说的:马特的解决了工作的一点点,但我得到的东西设置为我的作品。有一件事我不喜欢他的初步解决方案,是这样的诗句:

return objectType == typeof(ICog); 

按照这个模式,你就需要有您收到过线每个抽象类型JsonConverter。这是低于我的情况理想,所以我创建了一个通用JsonConverter这样:

public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T> 
{ 
    private readonly IUnityContainer Container; 
    public TalonJsonConverter(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)会在这种情况下给你一个可疑的强制性警告。

希望别人认为这有用!

+0

尝试使用'JsonSerializerSettings'类的'TypeNameHandling.All'并将其传递给json串行器 –

+0

[JSON.NET中反串行化的接口接口]可能的重复(http://stackoverflow.com/questions/5780888/ cast-interfaces-for-deserialization-in-json-net) –

+0

[使用Json.NET转换器反序列化属性](http://stackoverflow.com/questions/2254872/using-json-net-converters-to -deserialize-properties) – nawfal

回答

22

您需要为Json.Net提供一个自定义序列化程序来告诉它如何处理子轮齿。例如:

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

CogConverter需要从JsonConverter继承和指定它CanConvertICog接口。也许沿线的东西:

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); 
    } 
} 

我建议您注册您的JsonSerializerSettings与您的IoC容器在这种情况下。如果序列化程序不能负责实际构建Cog本身,您也可以考虑授予对容器的访问权限CogConverter;这一切都取决于你的特定架构。

编辑

经过进一步的阅读,它好像你可能会寻找具体如何使用IoC的人口创造了ICog。我用以下为我ReadJson的一部分:你希望你的DetermineConcreteType方法内部

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填充它,使用自定义类型。

+1

谢谢,马特。我会稍微说一下,看看它是否有效。 – dparsons

+0

随着一点点工作,这是正确的答案。我很好奇,你的'DetermineConcreteType'方法是做什么的? – dparsons

+0

在我们的系统中,我们看一下它的一些属性来确定一个正确的子类型(我们的接口与实现不是1:1) - 我能想到的一个通用的属性是一个下拉表示付款方式(信用卡vs银行等) - 每个都有不同的字段,但下拉的值可以指示该类型。如果你有你想要共享的代码作为答案的一部分,我很乐意更新我的代码以包含更完整的解决方案。 –

相关问题