C# 使用json.net将无法识别的类型反序列化为现有的默认未知对象

C# 使用json.net将无法识别的类型反序列化为现有的默认未知对象,c#,.net,json,asp.net-web-api,json.net,C#,.net,Json,Asp.net Web Api,Json.net,我有一个API客户端,它从ASP.NET Web API接收JSON序列化数据。序列化和反序列化使用JSON.Net进行。序列化的JSON使用typenameholling=typenameholling.Objects包含类型信息,这在正常用例中正常工作 问题 问题来自这样一个事实:服务器端的域模型经常更改,但消费者不一定立即获取这些更新 发生这种情况时,使用者请求模型列表,但序列化会引发错误,使用者根本看不到任何返回的模型,即使许多返回对象列表中只有一个未知 我知道我可以用ErrorCont

我有一个API客户端,它从ASP.NET Web API接收JSON序列化数据。序列化和反序列化使用JSON.Net进行。序列化的JSON使用
typenameholling=typenameholling.Objects包含类型信息,这在正常用例中正常工作

问题 问题来自这样一个事实:服务器端的域模型经常更改,但消费者不一定立即获取这些更新

发生这种情况时,使用者请求模型列表,但序列化会引发错误,使用者根本看不到任何返回的模型,即使许多返回对象列表中只有一个未知

我知道我可以用
ErrorContext.Handled=true来消化错误但这会吞下每一个错误,我真的不想这样

期望的行为/域示例 我想要的是将这些“无法识别”的项序列化为专门定义的未知项。如果更现实的话,我也愿意将它们序列化为最基本的类(尽管现在是抽象的)

我希望解决方案是灵活的,当一个新类型(下面的域示例中的新类型水果)添加到域中时,它只需要添加一次。我不想在序列化特定的类中手动注册水果

最后,我希望能够在弹出窗口时保持对其他类型未处理错误的可见性

下面是一个示例--请注意我的简化示例域:

模型
公共类响应
{
公共int响应ID{get;set;}
公共水果{get;set;}
}
公共抽象类水果
{
公共字符串颜色{get;set;}
公共十进制权重{get;set;}
}
公共级香蕉:水果
{
公共十进制长度{get;set;}
}
公营苹果:水果
{
public int WormCount{get;set;}
}
公共类未知水果:水果
{
//随便
}
脚本 现在,假设客户机请求水果,服务器返回
FruitResponse
对象列表。只要这些物体里面的水果是苹果和香蕉,就没有问题。但是,如果在服务器端添加了新的水果类型“Orange”,并且返回的JSON的
$type
属性反映了这一点,则请求将失败

我希望橘子(以及任何可能的芒果、草莓等)被反序列化为未知果实。这样消费者就知道有额外的水果,看到这些对象的水果响应属性(
FruitId
),以及基本水果属性。因此,服务器端的新添加不会为客户端创建破坏性的更改。可以忽略来自服务器的任何特定于橙色的属性

显然,我只希望水果类的物品有这种行为。它们都将继承自
Fruit
基类,而且它们都将位于Fruit名称空间中

我知道所有新的水果都将添加到同一名称空间,所以我想知道在反序列化时是否有方法在
$type
字段中检查这一点

如果返回一个
蔬菜
Foo
,我可以接受序列化失败

我试过的 我尝试在自定义
ISerializationBinder
中捕获一个错误

    public Type BindToType(string assemblyName, string typeName)
    {
        try
        {
            return binder.BindToType(assemblyName, typeName);
        }
        catch (Exception ex)
        {
            return typeof(UnknownFruit);
        }
    }
但这不仅看起来有点黑客(将异常用于控制流),而且也不起作用;我得到了这个错误(忽略奇怪的名称空间,这是因为我在linqpad中玩):

JSON“UserQuery+UnknownFruit,query_tykmkh,版本=0.0.0,区域性=中性,PublicKeyToken=null”中指定的类型与“UserQuery+Fruit,query_rraqao,版本=0.0.0,区域性=中性,PublicKeyToken=null”不兼容。路径“仪器$type”,第1行,位置124

它也不允许我探测
$type
以查看它是否位于正确的名称空间中

我也知道我可以反序列化到expando对象,但我希望最终结果是强类型的

这里的正确方法似乎是使用定制的
JsonConverter
,但我看到的使用该选项的方法涉及到手动向转换器注册模型,这是我想要避免的

我确实可以控制服务器和客户端代码,因此我可以在任何一方实现任何潜在的更改


非常感谢您的帮助。

您能更改服务器返回的JSON吗?Json.NET的
“$type”
功能在这里并不理想,因为
ISerializationBinder
没有传递预期的基类型。我可以--您有什么建议?我想确保它绑定到了正确的东西,因为域中存在一些命名冲突,而且所有的结果都是派生的结果,我希望它们序列化为派生的结果。使用自定义转换器可以帮助您。在问题本身中,我建议您手动添加自己的
“type”
属性,然后在自定义
JsonConverter
中查找具体类型。这些机制允许您添加默认情况,也可以避免使用
typenameholling
。这是有道理的,但它需要我在转换器内为每个类型显式创建映射,对吗?如果可能的话,我想避免这种情况。转换器中的已知类型列表是否可以通过反射或其他机制自动填充(不会对性能造成太大影响)?