5

我有一个 Web 客户端,它调用我的 WCF 业务服务层,而后者又调用外部 WCF 服务来获取实际数据。最初,我认为我会使用 DTO 并在不同的层中有单独的业务实体......但我发现提倡 DTO 的琐碎示例,嗯,琐碎。我看到太多重复的代码,没有太多好处。

考虑我的域:

示例域 我有一个 UI 屏幕(Asp.net MVC 视图),它显示了患者的药物列表、不良反应(药物之间)以及患者可能患有的任何临床状况(如抑郁症或高血压)。我的域模型从顶层开始:

   MedicationRecord
      List<MedicationProfile> MedicationProfiles
      List<AdverseReactions> Reactions
      List<ClinicalConditions> ClinicalConditions

   MedicationProfile is itself a complex object
      string Name
      decimal Dosage
      Practitioner prescriber 

   Practioner is itself a complex object
      string FirstName
      string LastName
      PractionerType PractionerType
      PractionerId Id
      Address Address    

      etc.

此外,在发出 WCF 请求时,我们有一个请求/响应对象,例如

   MedicationRecordResponse
      MedicationRecord MedicationRecord
      List<ClientMessage> Messages
      QueryStatus Status

   and again, these other objects are complex objects
   (and further, complicates matter is that they exist in a different, common shared namespace)

在这一点上,我的倾向是 MedicationRecordResponse我的 DTO。但是在纯 DataContracts 和 DTO 以及设计分离中,我应该这样做吗?

   MedicationRecordResponseDto
      MedicationRecordDto
      List<ClientMessageDto> 
      QueryStatusDto

   and that would mean I then need to do
      MedicationProfileDto
      PractitionerDto
      PractitionerTypeDto
      AddressDto
   etc.

因为我已经在屏幕上显示了几乎所有信息,所以我有效地为我拥有的每个域对象创建了 1 个 DTO。

我的问题是——你会怎么做?你会继续创建所有这些 DTO 吗?或者您只是在单独的程序集中共享您的域模型?

以下是其他似乎相关的问题的一些读物:

  1. WCF 合约知道域
  2. SOA 中转换层的替代方案:WCF
  3. SOA 问题:暴露实体
4

3 回答 3

6

看看优秀的文章

上面的链接不起作用,看起来像一个域问题(我希望它会得到修复),这里是来源:

于 2012-07-27T05:39:49.987 回答
3

我一直厌恶由 DTO 导致的重复的类层次结构。这似乎是对DRY原则的公然违反。但是,经过仔细研究,DTO 和相应的一个或多个实体扮演着不同的角色。如果您确实在应用领域驱动设计,那么您的领域实体不仅包含数据,还包含行为。相比之下,DTO 仅携带数据并充当域和 WCF 之间的适配器。所有这些在六边形架构(也称为端口和适配器以及洋葱架构)的上下文中更有意义. 您的域是核心,WCF 是一个将您的域暴露在外部的端口。DTO 是 WCF 功能的一部分,如果您同意它是必要的邪恶,那么您的问题就会从试图消除它们转变为拥抱它们,而是关注如何促进 DTO 和域对象之间的映射。一个流行的解决方案是AutoMapper这减少了您需要编写的样板映射代码的数量。除了缺点之外,DTO 还带来了很多好处。一是它们在您的域实体和外部世界之间提供了一个缓冲区。这对重构有很大帮助,因为您可以很好地封装核心域。另一个好处是您可以设计您的 DTO,以便它们满足服务使用者的要求,这些要求可能并不总是与您的域对象的形状完全一致。

于 2012-07-27T05:09:51.620 回答
3

就个人而言,我不喜欢使用 MessageContract 作为实体。不幸的是,我有一个使用 MessageContract 作为实体的现有 WCF 服务——即数据直接在数据访问层中填充到 MessageContract。不涉及翻译层。

我有一个使用此服务的现有 C# 控制台应用程序客户端。现在,我有一个新要求。我需要在实体中添加一个新字段。这不是客户需要的。新字段仅用于服务中的内部计算。我必须在 MessageContract 中添加一个名为“LDAPUserID”的新属性,它也充当实体。

这可能会也可能不会破坏客户端,具体取决于客户端是否支持Lax Versioning。请参阅服务版本控制

很容易错误地认为添加新成员不会破坏现有客户。如果您不确定所有客户端都可以处理松散的版本控制,建议使用严格的版本控制指南并将数据合约视为不可变的。

有了这个经验,我相信使用 MessageContract 作为实体是不好的。

另外,请参阅MSDN - 服务层指南

设计在业务实体和数据合同之间转换的转换对象。

参考:

  1. 如何序列化 NHibernate 映射对象的所有属性?
  2. 使用 WCF 从类库中公开对象
  3. 仅序列化属性子集
于 2013-04-05T08:04:19.153 回答