一尘不染

使ServiceStack保留类型信息

c#

我正在使用ServiceStack对一些对象进行序列化和反序列化为JSON。考虑以下示例:

public class Container
{
    public Animal Animal { get; set; }
}

public class Animal
{
}

public class Dog : Animal
{
    public void Speak() { Console.WriteLine("Woof!"); }
}

var container = new Container { Animal = new Dog() };
var json = JsonSerializer.SerializeToString(container);
var container2 = JsonSerializer.DeserializeFromString<Container>(json);

((Dog)container.Animal).Speak(); //Works
((Dog)container2.Animal).Speak(); //InvalidCastException

最后一行引发InvalidCastException,因为Animal字段被实例化为Animal类型而不是Dog类型。我有什么办法可以告诉ServiceStack保留该特定实例属于Dog类型的信息?


阅读 180

收藏
2020-05-19

共1个答案

一尘不染

DTO中的继承是一个坏主意-
DTO应该尽可能自我描述,并且通过有效地使用继承,客户端不知道服务最终会返回什么。这就是为什么您的DTO类在大多数“基于标准”的序列化程序中将无法正确反序列化的原因。

没有足够的理由在DTO中拥有接口(并且很少有理由在POCO模型上拥有接口),这是一种习惯,使用接口来减少应用程序代码中的耦合,这种想法被无意地泄漏到了DTO中。但是跨过程边界,接口仅增加了耦合(仅减少了代码),因为使用者不知道要反序列化的具体类型,因此接口必须发出特定于序列化的实现提示,这些提示现在将C#问题嵌入到了连线上(所以现在甚至C#名称空间将破坏序列化),现在限制了您的响应被特定的序列化器使用。C#上的泄漏问题违反了实现互操作性服务的核心目标之一。

由于JSON规范中没有“类型信息”的概念,因此为了使继承在JSON序列化程序中起作用,它们需要 发出 JSON
线格式专有扩展 以包括此类型信息-
现在将您的JSON有效负载耦合到特定的JSON序列化程序的实现。

ServiceStack的JsonSerializer将此类型信息存储在
__type
属性中,并且由于它可能使有效负载膨胀,因此只会针对需要它的类型(即Interfaces,后期绑定object类型或abstract类)发出此类型信息。

因此,解决方案是更改Animal接口抽象 类,但是建议不要在DTO中使用继承。

2020-05-19