asp.net-mvc - abp - asp net boilerplate




服务应该总是返回DTO,还是他们也可以返回域模型? (4)

它在域模型离开业务层(服务层)时感觉不对,

让你觉得你正在把胆量拉出来吗? 根据Martin Fowler的说法:服务层定义了应用程序的boundery,它封装了域。 换句话说,它可以保护域名。

有时服务需要返回域中未定义的数据对象

你能提供一个这个数据对象的例子吗?

如果我们应该严格遵守DTO,是否应该在服务层中定义它们?

是的,因为响应是您的服务层的一部分。 如果它被定义为“其他地方”,那么服务层需要引用“其他地方”,为您的烤宽面条添加一个新图层。

是否可以将域模型一直返回给控制器,还是应该始终使用DTO与服务层进行通信?

DTO是一个响应/请求对象,如果将它用于通信,这是有意义的。 如果您在表示层(MVC-Controllers / View,WebForms,ConsoleApp)中使用域模型,则表示层紧密耦合到您的域,域中的任何更改都需要您更改控制器。

似乎创建与领域模型相同的DTO没有多大意义)

这是DTO对新眼睛的缺点之一。 现在,你正在考虑重复代码 ,但是随着项目的扩展,它会变得更有意义,特别是在团队环境中,不同的团队被分配到不同的层。

DTO可能为您的应用程序增加额外的复杂性,但您的图层也是如此。 DTO是您系统的一个昂贵功能,它们不会免费。

为什么要使用DTO

本文提供了使用DTO的优点和缺点, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html ://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

总结如下:

何时使用

  • 对于大型项目。
  • 项目寿命10年及以上。
  • 战略性,关键任务应用。
  • 大型团队(超过5人)
  • 开发人员在地理上分布。
  • 域和表示是不同的。
  • 减少开销数据交换(DTO的最初目的)

何时不使用

  • 中小型项目(最多5名成员)
  • 项目寿命是2年左右。
  • GUI,后端等没有单独的团队。

对DTO的争论

与DTO的争论

  • 如果没有DTO,演示文稿和领域紧密结合。 (这对于小型项目来说是可以的。)
  • 接口/ API稳定性
  • 可以通过返回仅包含那些绝对需要的属性的DTO来为表示层提供优化。 使用linq-projection ,你不必拉整个实体。
  • 为了降低开发成本,请使用代码生成工具

我正在(重新)设计大型应用程序,我们使用基于DDD的多层体系结构。

我们拥有数据层(存储库实现),域层(域模型和接口 - 存储库,服务,工作单元的定义),服务层(服务实现)的MVC。 到目前为止,我们在所有层中使用域模型(主要是实体),并且我们仅将DTO用作视图模型(在控制器中,服务返回域模型和控制器创建视图模型,并将其传递给视图)。

我读过无数关于使用,不使用映射和传递DTO的文章。 我知道没有任何明确的答案,但我不确定是否可以或不从服务返回到控制器的域模型。 如果我返回域模型,它仍然不会传递给视图,因为控制器总是创建视图特定的视图模型 - 在这种情况下,它看起来是合法的。 另一方面,当域模型离开业务层(服务层)时,它感觉不对。 有时服务需要返回域中未定义的数据对象,然后我们必须将新对象添加到未映射的域,或者创建POCO对象(这很丑陋,因为有些服务返回域模型,有些有效地返回DTO)。

问题是 - 如果我们严格使用视图模型,将域模型一直返回给控制器是否可行,还是应该始终使用DTO与服务层进行通信? 如果是这样,可以根据需要调整域模型吗? (坦率地说,我不这么认为,因为服务应该消费域名。)如果我们应该严格遵守DTO,是否应该在服务层中定义它们? (我认为是这样)有时很明显我们应该使用DTO(例如,当服务执行大量业务逻辑并创建新对象时),有时很明显我们应该只使用域模型(例如,当会员服务返回贫血的用户s) - 创建与域模型相同的DTO似乎没有多大意义) - 但我更喜欢一致性和良好实践。

文章域与DTO vs ViewModel - 如何以及何时使用它们? (还有一些其他文章)与我的问题非常相似,但它不回答这个问题。 文章我应该使用EF来实现存储库模式的DTO吗? 也是相似的,但它不处理DDD。

免责声明:我不打算使用任何设计模式,因为它存在并且很花哨,另一方面,我想使用好的设计模式和实践,因为它有助于设计整个应用程序,有助于分离至少目前来说,即使使用特定模式也不是“必要的”。

一如既往,谢谢。


到目前为止,我们在所有层中使用域模型(主要是实体),并且我们仅将DTO用作视图模型(在控制器中,服务返回域模型和控制器创建视图模型,并将其传递给视图)。

由于域模型为整个应用程序提供术语( 无处不在的语言 ),所以最好广泛使用域模型。

使用ViewModels / DTOs的唯一原因是在应用程序中实现MVC模式以分离View (任何类型的表示层)和Model (域模型)。 在这种情况下,您的演示文稿和领域模型是松散耦合的。

有时服务需要返回域中未定义的数据对象,然后我们必须将新对象添加到未映射的域,或者创建POCO对象(这很丑陋,因为有些服务返回域模型,有些有效地返回DTO)。

我假设你谈论应用程序/业务/域逻辑服务。

我建议你尽可能地返回域实体。 如果需要返回附加信息,则返回包含多个域实体的DTO是可以接受的。

有时候,使用第三部分框架的人(通过域实体生成代理)面临着将域实体从服务中暴露出来的困难,但这只是错误用法的问题。

问题是 - 如果我们严格使用视图模型,将域模型一直返回给控制器是否可行,还是应该始终使用DTO与服务层进行通信?

我认为这足以在99.9%的情况下返回域实体。

为了简化DTO的创建并将您的域实体映射到它们中,您可以使用https://github.com/AutoMapper/AutoMapper


我迟到了这个派对,但这是一个很普遍而且很重要的问题,我觉得我不得不回应。

“服务”是指Evan's在蓝皮书中描述的“应用层”吗? 我会假设你这样做,在这种情况下,答案是他们不应该返回DTO。 我建议阅读蓝皮书中的第4章,题为“隔离域”。

在那一章中,埃文斯对这些图层进行了如下说明:

将一个复杂的程序分成多个层。 在每个层次内开发具有内聚性的设计,并且仅依赖于下面的图层。

这有很好的理由。 如果您使用偏序的概念作为衡量软件复杂性的指标,那么让一个图层依赖于它上面的图层会增加复杂性,从而降低可维护性。

将这个应用于您的问题,DTO实际上是一个适配器,它是用户界面/表示层的关注点。 请记住,远程/跨进程通信正是DTO目的 (值得注意的是,在那篇文章中,Fowler也反对DTO作为服务层的一部分,尽管他并不一定要谈论DDD语言)。

如果您的应用程序层依赖于这些DTO,则它取决于自身之上的层,并且您的复杂性增加。 我可以保证这会增加维护软件的难度。

例如,如果您的系统与其他几个系统或客户端类型接口,每个系统都需要自己的DTO,会发生什么? 你怎么知道你的应用服务的哪个DTO应该返回哪个DTO? 如果你选择的语言不允许重载基于返回类型的方法(在这种情况下是服务方法),你甚至可以解决这个问题? 即使你想出了一个办法,为什么违反你的应用层来支持表示层的关注?

实际上,这是以意大利式细面条建筑结束的一条道路。 我以我自己的经历见过这种权力下放和结果。

在我目前工作的地方,我们的应用层中的服务返回域对象。 我们不认为这是一个问题,因为接口(即UI /表示层)取决于它下面的域层。 而且,这种依赖性被最小化为“仅参考”类型的依赖性,因为:

a)接口层只能将这些Domain对象作为通过调用Application层获得的只读返回值来访问

b)应用层中的服务方法仅接受在该层中定义的“原始”输入(数据值)或对象参数(以在必要时减少参数计数)作为输入。 具体而言,应用程序服务从不接受域对象作为输入。

接口层使用接口层本身内定义的映射技术来将域对象映射到DTO。 同样,这使得DTO专注于由接口层控制的适配器。


根据我的经验,你应该做一些实用的事情。 “最好的设计是最简单的设计” - 爱因斯坦。 这就是...

如果我们严格使用视图模型,可以将域模型一直返回给控制器,还是应该始终使用DTO与服务层进行通信?

绝对没关系! 如果您有域实体,DTO和View Models然后包括数据库表,则应用程序中的所有字段将在4个地方重复。 我曾经在Domain Entities和View Models工作得很好的大型项目上工作过。 唯一的解释是,如果应用程序是分布式的,并且服务层驻留在另一台服务器上,在这种情况下,为了序列化的原因,DTO需要通过线路发送。

如果是这样,可以根据需要调整域模型吗? (坦率地说,我不这么认为,因为服务应该消费域名。)

一般来说,我会同意并且说不,因为域模型通常是业务逻辑的反映,并且通常不会被该逻辑的消费者所塑造。

如果我们应该严格遵守DTO,是否应该在服务层中定义它们? (我想是这样。)

如果您决定使用它们,我会同意并且说服务层是一个完美的地方,因为它将在一天结束时返回DTO。

祝你好运!





domain-driven-design