ServiceStack请求和响应对象

是否可以(阅读良好实践)重复使用POCO进行请求和响应DTO。 我们的POCO是轻量级的(ORM Lite),只有属性和一些装饰属性。

或者,我应该为请求和/或响应创建其他对象吗?

谢谢,

我会说这取决于你的系统,最终它有多大和复杂,并且有可能成为。

ServiceStack文档未指定您应使用的设计模式。 最终,它提供了将数据库模型POCO与DTO分离的灵活性,但它也为它们的重用提供了支持。

使用OrmLite时:

OrmLite的设计使您可以重复使用数据模型POCO作为请求和响应DTO。 从ServiceStack文档中可以看出 ,这是框架的有意设计目标:

Micro ORMS中使用的POCO特别适合作为DTO重新使用,因为它们不包含重ORM具有的任何循环引用(例如EF)。 OrmLite更进一步,从NoSQL的playbook中借用页面,其中任何复杂的属性,例如List在无模式文本字段中透明地填充,促进了RDBMS关注不受限制的无摩擦Pure POCOS的设计。

考虑:

如果您选择重新使用POCO,因为它受支持,您应该知道在某些情况下使用单独的请求和响应DTO会更聪明。

在许多情况下,这些POCO数据模型已经形成了良好的DTO,可以直接返回,而不是映射到特定于域的DTO。

^并非所有情况 。 有时,选择设计模式的难度预计会出现可能不适合重复使用的情况。 所以希望情景有助于说明潜在的问题。

场景:

  • 您有一个系统,用户可以在其中注册您的服务。
  • 作为管理员,您可以列出服务的用户。

如果你采用OrmLite POCO重用方法,那么我们可能会有这个User POCO:

 public class User { [PrimaryKey, AutoIncrement, Alias("Id")] public int UserId { get; set; } public string Username { get; set; } public string Password { get; set; } public string Salt { get; set; } public bool Enabled { get; set; } } 

当您创建“创建用户”请求时,您将User POCO的UsernamePassword填充为对服务器的请求。

我们不能将此POCO推送到数据库中,因为:

  • Password字段中的Password为纯文本。 我们是优秀的程序员,安全性很重要,因此我们需要创建一个salt,我们将其添加到Salt属性中,并使用salt哈希Password并更新Password字段。 好的,这不是一个主要问题,几行代码将在插入之前对其进行排序。

  • 客户端可能已设置UserId ,但对于create,这不是必需的,并且将导致我们的数据库查询无法插入。 因此我们必须在插入数据库之前默认此值。

  • Enabled属性可能已与请求一起传递。 如果有人设置了这个怎么办? 我们只想要处理UsernamePassword ,但现在我们必须考虑影响数据库插入的其他字段。 同样,他们可以设置Salt (虽然这不会是一个问题,因为我们无论如何都会覆盖这个值。)所以现在你已经添加了validation。

但现在考虑我们何时返回List

如果您重新使用POCO作为响应类型,则有许多字段不希望暴露给客户端。 做起来并不聪明:

 return Db.Select(); 

由于您没有用于列出用户的紧密专用响应,因此需要在逻辑中删除Password哈希和Salt ,以防止在响应中将其序列化。

还要考虑在注册用户期间,作为创建请求的一部分,我们想询问是否应该发送欢迎电子邮件。 所以我们会更新POCO:

 public class User { // Properties as before ... [Ignore] // This isn't a database field public bool SendWelcomeEmail { get; set; } } 

我们现在拥有仅在用户创建过程中有用的附加属性。 如果您反复使用User POCO,您会发现随着时间的推移,您添加的内容越来越多,不适用于某些上下文。

例如,当我们返回用户列表时,现在可以填充SendWelcomeEmail的可选属性 – 它只是没有意义。 然后很难维护代码。

要记住的一个关键事项是,在共享POCO对象时,它既可以用作请求,也可以用作响应对象: 作为响应发送的属性将在请求中公开。 您将不得不对请求进行更多validation,最终共享POCO可能无法节省成本。

在这种情况下,这样做不会容易得多:

 public class CreateUserRequest { public string Username { get; set; } public string Password { get; set; } public bool SendWelcomeEmail { get; set; } } public class UserResponse { public int UserId { get; set; } public string Username { get; set; } public bool Enabled { get; set; } } public class User { [PrimaryKey, AutoIncrement, Alias("Id")] public int UserId { get; set; } public string Username { get; set; } public string Password { get; set; } public string Salt { get; set; } public bool Enabled { get; set; } } 

我们现在知道当我们创建一个请求( CreateUserRequest )时,我们不必考虑UserIdSaltEnabled

当返回用户列表时,它现在是List ,客户端将无法看到我们不希望他们看到的任何属性。

对于查看代码,请求所需属性以及响应中将公开的内容的其他人来说,这一点很清楚。

摘要:

对不起,这是一个非常长的答案,但我认为这解决了分享POCO的一个方面,有些人错过了,或者最初没有掌握,我就是其中之一。

  • 是的,您可以重复使用POCO进行请求和响应。
  • 文档说这样做是可以的。 实际上它是设计的。
  • 在许多情况下,重复使用会很好。
  • 有些情况下它不合适。 (我的场景试图展示这一点,但是当你发展自己的真实情况时,你会发现。)
  • 考虑可能会暴露多少其他属性,因为您的共享POCO尝试支持多个操作,以及可能需要多少额外的validation工作。
  • 最终,这是关于你维护的舒适度。

希望这可以帮助。

我们有其他方法,我的答案是固执己见的。

因为我们不仅使用C#客户端,而且主要使用JavaScript客户端。

请求和响应DTO,路由和数据实体之间进行协商

客户和前端分析师。 它们是详细forms的规格的一部分。

即使“客户”,在某些情况下,也是我们的产品UI。

这些DTO在没有重要原因的情况下不会改变,并且可以在双方重复使用。

但是数据层中的对象可以是相同或部分类或不同,

它们可以在内部更改,包括敏感或工作流信息,

但它们必须与API的规范兼容。

我们首先使用API ,而不是数据库或ORM。

  Person { ... } Address { ... } ResponceDTO { public bool success {get; set;} public string message {get; set;} public Person person {get; set;} public List
addresses {get; set;} //customer can use the Person & Address, which can be the same or different //with the ones in the data-layer. But we have defined these POCO's in the specs. } RequestDTO { public int Id {get; set;} public FilteByAge {get; set;} public FilteByZipCode {get; set;} } UpdatePersonRequest { public int Id {get; set;} public bool IsNew {get; set;} public Person person {get; set;} public List
addresses {get; set;} }

我们不公开请求或响应DTO。

人员和地址与客户协商并在API规范中引用。

它们可以与数据层内部实现相同或部分或不同。

客户将使用它们到他们的应用程序或网站或移动设备。

但重要的是我们首先设计和协商API接口。

我们经常使用requestDTO作为业务层函数的参数,

返回响应对象或集合。

通过这种方式,服务代码是业务层前面的瘦包装器。

  ResponseDTO Get(RequestDTO request) { return GetPersonData(request); } 

同样来自ServiceStack wiki, API-First开发方法

鉴于您可以公开数据对象的结构(如果这是一个公开使用的API),这不会是一个问题。 否则,Restsharp将与简单的POCO一起使用:)

我认为这一切都取决于你如何使用你的DTO,以及你希望如何平衡代码的可重用性和可读性。 如果您的请求和响应都使用了DTO上的大部分属性,那么您将获得大量的可重用性,而不会降低可读性。 例如,如果您的请求对象有10个属性(反之亦然),但您的响应只需要其中的1个,那么如果您的响应对象上只有1个属性,则有人可以提出一个更容易理解/读取的参数。

总之,良好的做法就是干净的代码。 您必须根据您的代码是否易于使用和阅读来评估您的特定用例。 另一种思考方式是为下一个阅读它的人编写代码,即使那个人就是你。