【问题标题】:Contract-First SOA: Designing Business Domain: WCF合同优先 SOA:设计业务领域:WCF
【发布时间】:2012-03-18 22:18:34
【问题描述】:

我正在使用 WCF 构建一个全新的系统。我将对基于面向服务的概念构建的服务使用合同优先方法。我有一个返回用户银行帐户详细信息的服务操作。该帐户可以是“FixedAccount”或“SavingsAccount”类型。我将服务设计如下。

[ServiceContract]
interface IMyService
{
[OperationContract]
AccountSummary AccountsForUser(User user);
}


[DataContract]
class AccountSummary
{
 [DataMember]
 public string AccountNumber {get;set;}

 [DataMember]
 public string AccountType {get;set;}
}

这么多就好了。

现在,我需要为此服务开发业务域。我可以想到两种选择(任何新方法总是受欢迎的)

1) 方法 1:提出一个 BankAccount 基类。从它派生的专门类是“FixedAccount”和“SavingsAccount”。 BankAccount 将有一个方法作为 Transfer(string toAccount)。这成为我们熟悉且有效的 OOAD。这涉及在 AccountSummary DTO 和 FixedAccount/ SavingsAccount 域类之间进行映射的映射器。

2) 方法2:不使用映射器翻译层。

问题

1) 假设我正在使用方法 1。是否有任何文章/教程解释了如何根据 DTO 中的 AccountType 值将 AccountSummary DTO 映射到 FixedAccount/ SavingsAccount 域类(条件映射)?

2) 如何完成方法 2 中的任务?


阅读:-

  1. http://www.soapatterns.org/service_facade.php

  2. SOA architecture data access

  3. Designing services and operations in WCF

  4. WCF Data Contract and Reference Entity Data?

  5. When does logic belong in the Business Object/Entity, and when does it belong in a Service?

【问题讨论】:

  • 您在使用什么 ESB,或者您的 SOA 层是如何实现的?
  • @JamesBlack SOA 将使用 WCF 实现
  • WCF 是针对 web 服务的,但是仅仅因为你建立了一个 web 服务并不能使它成为一个 SOA 层。如果您在用户和 Web 服务之间放置一条消息总线,那么现在我们就有了更多面向服务的东西。对于您的问题,我将有两个不同的服务,但让它们转到一个公共控制器。

标签: .net wcf oop c#-4.0 soa


【解决方案1】:

首先 - 您需要了解您是否真的需要成熟的 SOA。

SOA 基本上意味着每个操作都通过将我们的系统与其他系统解耦的服务进行。在极少数情况下(如果应用程序变得非常庞大)- 系统的一部分来自另一部分。

您的应用程序会与任何其他应用程序“对话”吗?

如果不是,而您只是在构建单体网站,请解放您的思想,摒弃 SOA 废话。否则你最终会得到无用的抽象层。

这是您可以应用第二种方法的唯一方法,因为如果不将域模型映射到其他东西,您就无法完全解耦。


如果真的需要 SOA - 我们必须封装我们的域模型,从外部世界隐藏。这意味着 - 从我们的模型到 DTO 必须有某种映射。

是否有任何文章/教程解释了如何将 AccountSummary DTO 映射到 FixedAccount/ SavingsAccount

映射本身并不复杂。这是映射对象的一种简单方法:

class AccountSummary{
  public string InterestingThing {get; set;}
  public string AnotherThing {get; set;}
}
class AccountSummaryMapper{
   public static Map(BankAccount a){
    return new AccountSummary{
        InterestingThing=a.SomethingSomething,
        AnotherThing=a.Something.Else.ToString()
      };
   }
}
var accountSummary=
  AccountSummaryMapper.Map(myBankAccount);

这似乎无效。像Automapper 这样的对象到对象映射器可以提供帮助。阅读教程,它应该足以让你继续前进。想法并不难 - 您创建地图,在应用程序启动时告诉 Mapper 它们,然后使用 Mapper 通过给定配置映射您的对象。


另外 - 考虑映射方向。 Good object oriented code 通常意味着您要么提出问题,要么告诉对象去做事情。对象不应该知道其他对象职责的内部运作。

类比 - 父母完成孩子的家庭作业是不好的,因为孩子不会学到任何东西,父母会承担不必要的工作。相反 - 父母应该强迫孩子自己工作。

将 AccountSummary 直接映射到 BankAccount 并重新设置其状态就像做作业一样。应该不需要这样的映射。相反 - 将 BankAccount 告诉 BankAccount.DoHomework(pencil, copybook, someStrongWords)。


发展业务领域

您不开发业务领域。您开发的领域模型只是业务领域的反映,旨在解决特定问题。

【讨论】:

  • 谢谢。就一个问题。如果我不使用 SOA,我为什么要使用 WCF?我可以直接参考项目,不是吗?
  • @Lijo 真的。 WCF 将是不必要的。另外 - 如果您确实使用 SOA,WCF 不是强制性的。有很好的选择,比如nservicebus.com
【解决方案2】:

在弄清楚这部分之前,您需要确定您的客户将从每个服务方法调用中获得什么。客户需要 FixedAccount/SavingsAccount,还是真的只需要 AccountSummary?

如果方法(如您的示例中的方法)只返回 AccountSummary,那么一种简单的方法是向 BankAccount 添加一个创建 AccountSummary 的方法。然后当你想要返回一些东西时(不管它是什么类型的账户,但假设你的两个账户都是从 BankAccount 继承的),你只需这样做:

return someAccount.ToSummary()

有些人会告诉你,它不是“纯粹的”,因为你的 BankAccount 类现在知道你的 AccountSummary,但我个人一直发现它更容易使用。如果你不喜欢这样,像 AutoMapper 这样的工具也可以非常有效地做到这一点(正如其他答案中提到的那样)。

如果您返回某种派生类而不是实际类本身,则无法绕过将其映射到某个地方(如果您使用 AutoMapper 或自己编写一些东西)。避免必须进行任何映射的唯一方法是返回 BankAccount 本身,这不建议用于服务,因为对类的内部更改会影响服务。现在很容易记住这一点,但在 3 年后另一个开发人员进行维护时也很容易忘记它。映射也只发送您明确告诉它的服务内容,因此它再次有助于避免泄漏数据的错误。

BankAccount.ToSummary() 的内容很简单

public AccountSummary ToSummary()
{
    AccountSummary s = new AccountSummary();
    s.AccountNumber = AccountNumber();
    s.Balance = Balance()
    return s;
}

【讨论】:

    【解决方案3】:

    对于方法一,请考虑使用 AutoMapper 之类的工具,而不是手动实现映射。可以为你省去很多痛苦。 AutoMapper

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-24
      相关资源
      最近更新 更多