【发布时间】:2011-08-16 23:47:49
【问题描述】:
我正在开发一个 3 层应用程序(不是 3 层!),其中一个客户端应用程序运行在一个层(物理集群)上,它与另一个层上运行的服务应用程序和另一个层上的数据库服务器交互。该应用程序有很多业务规则、流程逻辑等,我认为它们应该在应用程序层和服务层都可用,以改善用户体验、减少对服务的调用以及消除冗余编码。
让我们用这个例子:在我的领域层,我有一个 Document 对象。此对象包含一个 AllowPublish 属性,该属性检查对象的内部状态,如果状态允许发布文档,则返回 true/false。该对象还有一个 Publish 方法,该方法通过将 IsPublished 标志设置为 true 并引发 Published 域事件来修改对象的内部状态以反映它正在发布的事实。
我有一个单独的 AuthorizationService 来确定是否允许当前用户发布,还有一个 DocumentRepository 可以将对象持久保存到数据库中。
在我的服务应用程序中,我的 DocumentService 有一个 PublishDocument 方法,该方法接受文档 ID,使用 id 从存储库中检索文档,检查 AllowPublish 属性,如果为真,调用 Publish 然后使用存储库保存更新的对象。
我对客户端的行为略有不同。在这种情况下,我使用 AllowPublish 属性来启用/禁用命令按钮。启用并单击后,我调用了一个服务代理,该代理公开了一个接受文档 ID 的 PublishDocument 方法。代理将调用传递给服务应用程序的同名 DocumentService 方法。
为了消除重复代码、共享业务逻辑、验证规则等,我将域对象放在一个单独的程序集中,由客户端应用程序和服务应用程序共享。这意味着客户端应用程序现在可以访问我的 Document 类的 Publish 方法,即使它只是相关的并且只能由我的服务应用程序使用。这让我重新考虑我正在采取的整个方法。
虽然我了解使用 DTO 在客户端和服务器之间传递状态,但我使用的是 .NET 3.5,据我所知,共享程序集是与客户端共享业务和验证规则的唯一方法应用。我有一些想法我可以去哪些其他方向,但希望在开始新的道路之前得到一些建议。
另一方面,我当前为客户实施的方法是我认为的一种迂回授权方法,这可能只是表明不同模型会更好的一个指标。就像我的服务器端服务应用程序中有一个 AuthorizationService 用于 DocumentService 执行授权一样,我有一个类似的代理,我的客户端代码使用它。这意味着我需要在客户端代码中添加另一层间接来支持授权,可能是 Controller 或 ViewModel。如果用例是有效的,那很好。
编辑
我可能需要澄清在编辑文档时 AllowPublish 属性是动态的。当第一次检索时,它可能是假的,但随着业务规则的满足,它会变为真。在客户端应用程序中运行业务规则使我们能够提供更丰富的用户体验。
【问题讨论】:
-
这可能是研究 CQRS 的好时机。这不是一小步,但从您所描述的情况来看,这可能是一个不错的选择。这个想法是为写入(命令)和读取(查询)建立单独的模型。这样,您的文档对象(又名 DDD 实体或聚合)将成为写入模型的一部分,而在读取模型上,您将拥有一个简单的 DTO,它具有已计算的所有属性 - DocumentDTO 的 AllowPublish 将是一个简单的布尔字段,每当更改 Document 实体时都会更新。如果您需要,我可以提供更多信息,但我认为 google 应该就足够了。
-
我实际上是在精神上实现 CQRS。例如,检索文档列表的查询方法实际上返回 DocumentInfo 对象,其中包含简单的只读属性(只不过是一个 DTO)。这些 DTO 仍然是从实际的域对象生成的,这些对象具有确定那些布尔属性(如 AllowPublish)将包含什么值的逻辑。虽然我喜欢 CQRS 背后的概念,但我不喜欢该实现,因为我发现它超出了 avg 开发人员的理解范围。因此,我尝试使用 R/O DTO 进行读取和使用域对象进行写入来保持简单。
-
我应该澄清一下:CQRS 失去了我,因为它是一个事务存储——这意味着我们存储的是事务,而不是状态。这对许多应用程序来说都很好,但我在努力中还没有遇到一个非常合适的案例。我不想爬过交易列表来查找我当前的状态,并且为汇总数据等实施服务所带来的额外开销太大了。我喜欢分离职责的想法,并且实际上已经实现了一个版本,其中查询是针对 CUBE 而不是实际的数据存储执行的。就在我来的时候。
-
我认为您是在暗示 CQRS 需要 EventSourcing。只是为了澄清 CQRS 并不意味着 EventSourcing。 CQRS 仅意味着使用域事件同步的命令和查询的单独模型。保留模型的方式取决于您。您不必使用 EventSourcing,但我鼓励您观看 Greg Young 的视频,作为 ES 的精彩演示。
标签: .net domain-driven-design soa