让 ServiceStack 保留类型信息 [英] Getting ServiceStack to retain type information

查看:22
本文介绍了让 ServiceStack 保留类型信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ServiceStack 将一些对象序列化和反序列化为 JSON.考虑这个例子:

I'm using ServiceStack to serialize and deserialize some objects to JSON. Consider this example:

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 类型的信息吗?

The last line throws a InvalidCastException, because the Animal field is instantiated as an Animal type, not a Dog type. Is there any way I can tell ServiceStack to retain the information that this particular instance was of the Dog type?

推荐答案

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

Inheritance in DTOs is a bad idea - DTO's should be as self-describing as possible and by using inheritance clients effectively have no idea what the service ultimately returns. Which is why your DTO classes will fail to de/serialize properly in most 'standards-based' serializers.

没有充分的理由在 DTO 中使用接口(在 POCO 模型上使用它们的理由也很少),使用接口来减少应用程序代码中的耦合是一种货物崇拜习惯,这些代码会被轻率地泄露到 DTO 中.但是跨进程边界,接口只会增加耦合(它只是在代码中减少),因为消费者不知道要反序列化的具体类型,所以它必须发出特定于序列化的实现提示,现在将 C# 关注点嵌入到线路上(所以现在甚至C# 命名空间将中断序列化),现在将您的响应限制为由特定的序列化程序使用.在线路上泄露 C# 问题违反了服务实现互操作性的核心目标之一.

There's no good reason for having interfaces in DTO's (and very few reasons to have them on POCO models), it's a cargo cult habit of using interfaces to reduce coupling in application code that's being thoughtlessly leaked into DTOs. But across process boundaries, interfaces only adds coupling (it's only reduced in code) since the consumer has no idea what concrete type to deserialize into so it has to emit serialization-specific implementation hints that now embeds C# concerns on the wire (so now even C# namespaces will break serialization) and now constrains your response to be used by a particular serializer. Leaking C# concerns on the wire violates one of the core goal of services for enabling interoperability.

由于 JSON 规范中没有类型信息"的概念,为了让继承在 JSON 序列化器中工作,它们需要JSON 线格式 包含此类型信息 - 现在将您的 JSON 有效负载耦合到特定的 JSON 序列化器实现.

As there is no concept of 'type info' in the JSON spec, in order for inheritance to work in JSON Serializers they need to emit proprietary extensions to the JSON wireformat to include this type info - which now couples your JSON payload to a specific JSON serializer implementation.

ServiceStack 的 JsonSerializer 将此类型信息存储在 __type 属性中,因为它可以显着膨胀有效载荷,只会为需要它的类型发出此类型信息,即 Interfaces、后期绑定 object 类型或 abstract 类.

ServiceStack's JsonSerializer stores this type info in the __type property and since it can considerably bloat the payload, will only emit this type information for types that need it, i.e. Interfaces, late-bound object types or abstract classes.

话虽如此,解决方案是将 Animal 更改为 Interfaceabstract 类,但建议不要在 DTO 中使用继承.

With that said the solution would be to change Animal to either be an Interface or an abstract class, the recommendation however is not to use inheritance in DTOs.

这篇关于让 ServiceStack 保留类型信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆