在阅读了一些ServiceStack wiki后,我对DTO有疑问,我希望你能提供帮助。
维基说:
在服务开发中,您的服务DTO提供您的技术无关服务层,您希望保持干净并尽可能“无依赖”,以实现最大的可访问性和潜在的重用。我们的建议是将您的服务DTO保存在一个单独的无部署组件中。 (https://github.com/ServiceStack/ServiceStack/wiki/New-API)
最后,您还可以使用之前更明确的客户端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库/框架。
如果我将所有请求 - 响应DTO打包到NET DLL,1#比2#更抽象!
这意味着: 如果将来某一天我不使用ServiceStack,则此DLL不需要任何更改。 (ServiceStack库/框架应该是基础设施而不是抽象)
如果我错了,请纠正我。
非常感谢。
答案 0 :(得分:1)
DTO应该具有的唯一依赖是无内容ServiceStack.Interfaces.dll
,因为它是可移植类库(PCL),几乎支持.NET运行的每个mobile or Desktop platform。 ServiceStack的接口.dll是必需的,以便能够在单个良性.dll中清晰地描述您的完整服务合同。
例如。 [Route]
元数据属性捕获托管远程服务的自定义路由,这是客户端需要知道的有关服务的必需信息,以便能够通过其已发布的自定义路由调用服务。同样,IReturn<T>
界面标记为您的服务返回提供强类型合约,这是启用ServiceStack succinct end-to-end Typed API的内容。基本上,ServiceStack.Interfaces是一个必需的扩展,可以在您的服务DTO中捕获您的整个服务合同。
即使您不使用ServiceStack,您仍然可以使用客户可以反省的良性ServiceStack.Interfaces.dll
来查找有关您的DTO和远程服务合同的更多信息。虽然我没有看到任何理由,如果你想要解开项目中的ServiceStack.Interfaces,你可以只复制你在DTO中使用的属性.dll将它从任何外部依赖项中解放出来。但这会影响您拥有通用服务客户端的能力,因为客户端库不知道这些嵌入式接口和属性,从而限制了使用它来启用丰富通用功能的能力。
为了支持非TypeScript等非.NET语言,ServiceStack会在生成的DTO中发出这些接口,因此它们不需要任何依赖。
同样在添加ServiceStack参考support of Swift 2.0或Java and Android中,这些额外的合同是在Java android客户端软件包中以惯用方式引用Swift IReturn
协议或IReturn<T>
接口发出的。什么使得简单的Typed API的ServiceStack能够在iOS和Android上启用。
设计API时应注意的是Service Layer is your most important contract。即,您的API的存在是为了允许消费者访问您的远程服务器功能,因此您的内部逻辑应该是隐藏的细节,而不应该影响API的外部表面区域。
请求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消费者将绑定(并且永远不会更改)的理想服务契约。请记住,您的服务的目标是为您的消费者提供可重复使用的功能,以便您的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的内置Authenticate
和AuthenticateResponse
请求和响应DTO。
我还建议您阅读此前面的答案以了解importance of DTO's and how it relates to the goals of a Service。