契约优先SOA:设计业务领域:WCF

时间:2012-02-29 12:12:39

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

我正在使用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(字符串toAccount)。这成为我们熟悉的&有效的OOAD。这涉及到映射器,用于在AccountSummary DTO和FixedAccount / SavingsAccount域类之间进行映射。

2)方法2 :不使用映射器转换层。

问题

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

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


READING: -

  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?

3 个答案:

答案 0 :(得分:3)

首先 - 你需要了解你是否真的需要全面的SOA。

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

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

如果没有,你只是建立巨石网站,释放你的思想,并削减SOA bullcrap。否则你最终会得到无用的抽象层。

这是你可以应用第二种方法的唯一方法,因为你不能完全解耦域模型而不将其映射到其他方法。


如果确实需要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(铅笔,字帖,一些强词)。


  

开发业务领域

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

答案 1 :(得分:2)

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

答案 2 :(得分: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;
}