获取 ServiceStack 以保留类型信息 [英] Getting ServiceStack to retain type information

查看:19
本文介绍了获取 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 模型上使用接口的理由很少),这是一种使用接口来减少应用程序代码耦合的习惯.但是跨越进程边界,接口只会增加耦合(它只是减少了代码),因为消费者不知道要反序列化成什么具体类型,所以它必须发出特定于序列化的实现提示,现在将 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 更改为 Interface抽象 类,但是建议不要在 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天全站免登陆