WCF消息&数据合同,DTO,域模型和共享程序集

时间:2012-07-27 04:32:07

标签: wcf domain-driven-design soa dto datacontract

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

考虑我的域名:

示例域 我有一个单独的UI屏幕(Asp.net MVC View),显示患者的药物清单,不良反应(药物之间)和患者可能患有的任何临床情况(如抑郁或高血压)。我的域名模型从顶层开始:

   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 contract know the domain
  2. Alternatives for Translation Layer in SOA: WCF
  3. SOA Question: Exposing Entities

3 个答案:

答案 0 :(得分:7)

答案 1 :(得分:3)

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

答案 2 :(得分:3)

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

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

这可能会也可能不会破坏客户端,具体取决于客户端是否支持Lax Versioning。请参阅Service Versioning

  

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

凭借这种经验,我认为将MessageContract用作实体并不好。

另请参阅MSDN - Service Layer Guidelines

  

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

参考文献:

  1. How do I serialize all properties of an NHibernate-mapped object?
  2. Expose object from class library using WCF
  3. Serialize subset of properties only