ServiceStack 零依赖请求-响应 DTO

ServiceStack zero dependency Request-Response DTOs

在阅读了一些 ServiceStack wiki 之后,我遇到了关于 DTO 的问题,我希望你能提供帮助。

wiki 说:

  1. 在服务开发中,您的服务 DTO 提供与技术无关的服务层,您希望保持清洁并尽可能 'dependency-free' 以实现最大的可访问性和潜在的重用。我们的建议是将您的服务 DTO 保存在一个独立的、基本上没有 dep 的程序集中。 (https://github.com/ServiceStack/ServiceStack/wiki/New-API)

  2. 最后,您还可以使用以前更明确的客户端 API(非常适合没有 IReturn<> 标记的情况): (https://github.com/ServiceStack/ServiceStack/wiki/New-API)

基于以上原因,我认为关于ServiceStack的最佳实践是: 我们应该使用 POCO 请求-响应 DTO 而不是继承自 IReturn<>。?

例如:

我们应该使用 1#:

public class AuthenticationRequest
{
    public string Name { get; set; }   
    public string Password { get; set; }
}

public class AuthenticationResponse
{
   public AuthenticationResponseType Result { get; set; }
   public UserInfoDto UserInfo { get; set; }
}

我们不应该使用 2#:

using ServiceStack;
public class AuthenticationRequest : IReturn<AuthenticationResponse>
{
    public string Name { get; set; }
    public string Password { get; set; }
}

public class AuthenticationResponse
{
   public AuthenticationResponseType Result { get; set; }
   public UserInfoDto UserInfo { get; set; }
}

因为1#是零依赖,所以2#对ServiceStack有依赖library/framework.

如果我把所有的Request-Response DTO打包成一个NET DLL,1#比2#更抽象!

这意味着: 如果将来有一天我决定不使用 ServiceStack,则此 DLL 不需要任何更改。 (ServiceStack library/framework 应该是基础架构而不是抽象)

如有错误请指正。

非常感谢。

DTO 唯一的依赖项应该是无实现的 ServiceStack.Interfaces.dll,因为它是一个便携式 Class 库 (PCL) 几乎支持 .NET 的每个 mobile or Desktop platform运行。 ServiceStack 的 Interfaces .dll 是必需的,以便能够在一个单一的良性 .dll 中清楚地描述您的完整服务合同。

例如。 [Route] 元数据属性捕获托管远程服务的自定义路由,这是有关您的服务的必需信息,客户需要知道这些信息才能通过其发布的自定义路由调用服务。同样,IReturn<T> 接口标记提供了关于您的服务 returns 的强类型合同,这正是启用 ServiceStack succinct end-to-end Typed API 的原因。本质上 ServiceStack.Interfaces 是一个必需的扩展,以便能够在您的服务 DTO 中捕获您的整个服务合同。

ServiceStack.Interfaces 可以在 ServiceStack 之外使用

即使您不使用 ServiceStack,您仍然可以使用良性的 ServiceStack.Interfaces.dll,客户端可以自省以找到有关您的 DTO 和远程服务合同的更多信息。虽然我没有看到任何理由,但如果您想分离项目中的 ServiceStack.Interfaces,您只需复制您在 DTO .dll 中使用的属性,将其从任何外部依赖项中释放出来。但这会影响您拥有通用服务客户端的能力,因为这些嵌入式接口和属性对于您的客户端库来说是未知的,从而限制了它使用它来启用丰富的通用功能的能力。

其他语言的服务契约接口和属性

为了支持 TypeScript 等非 .NET 语言,ServiceStack 在生成的 DTO 中发出这些接口,因此它们不需要任何依赖项。

同样在添加 ServiceStack 参考 support of Swift 2.0 or Java and Android 中,这些额外的合同是按照惯用方式发出的,引用 Swift IReturn 协议或 Java IReturn<T> 中的接口 android 客户端包,这也是启用简洁类型 API 的 ServiceStack 在 iOS 和 Android.

上启用的原因

服务设计

在设计 API 时应牢记的一点是 Service Layer is your most important contract。也就是说,您的 API 的存在是为了允许消费者访问您的远程服务器功能,因此您的内部逻辑应该是一个隐藏的实现细节,而不是应该影响 API 的外部表面积的东西。

Request DTO 定义了您的服务合同,我发现在其中使用 Request 后缀是一种丑陋的结构,会对外部 API 的可读性产生负面影响,例如这是带有 *Request 后缀的名词的典型示例:

var response = client.Get(new CustomerRequest { ... });

与使用请求 DTO 具有指示性并提供更好的服务功能可读性的动词相比:

var response = client.Get(new FindCustomers { ... });

您的请求 DTO 理想情况下应该是 动词grouped by call semantics and Response Type。具有 *Dto 后缀表明您的内部实现正在泄漏并影响您的外部 API 消费者将绑定(并且永远不应更改)的理想服务合同。请记住,您的服务的 objective 是为您的消费者提供可重复使用的功能,因此您的 impl 应该实现您发布的合同,而不是相反,它的实现决定了合同应该是什么。

考虑到这一点,我会重写您的 ServiceStack 示例,使其看起来像:

public class Authenticate : IReturn<AuthenticateResponse>
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class AuthenticateResponse
{
   public AuthenticationResult Result { get; set; }
   public UserInfo UserInfo { get; set; }
}

这最终类似于 ServiceStack 的内置 AuthenticateAuthenticateResponse 请求和响应 DTO。

我还建议阅读这个较早的答案以了解