Contract-First SOA: Designing Business Domain: WCF
Asked Answered
P

3

2

I am building a completely new system using WCF. I am going to use Contract-First Approach for a service which is to be built based on Service Oriented concepts. I have a service operation that returns a bank account details of a user. The account can be of type “FixedAccount” or “SavingsAccount”. I have designed the service as follows.

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


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

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

This much is fine.

Now, I need to develop the business domain for this service. I can think of two options (any new approach is always welcome)

1) Approach 1: Come up with a BankAccount base class. The specialized classes derived from it are “FixedAccount” and “SavingsAccount”. The BankAccount will have an method as Transfer(string toAccount). This becomes our familiar & effective OOAD. This involves mapper for mapping between AccountSummary DTO and FixedAccount/ SavingsAccount domain classes.

2) Approach 2: Without using mapper translation layer.

Questions

1) Suppose I am using approach 1. Is there any article/tutorial that explains how to map AccountSummary DTO to FixedAccount/ SavingsAccount domain classes based on the AccountType value in DTO (conditional mapping) ?

2) How do I achieve the task in approach 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?

Piranha answered 29/2, 2012 at 12:12 Comment(3)
What are you using for an ESB, or how is your SOA layer implemented?Leoni
@JamesBlack SOA will be implemented using WCFPiranha
WCF is for the webservice, but just because you stand up a webservice doesn't make it a SOA layer. If you put a message bus between the user and the webservice, now we have something more service-oriented. For your problem I would have two different services, but have them go to a common controller.Leoni
J
3

First of all - you need to understand if you really need full-blown SOA.

SOA basically means that every operation is going through service that decouples our system from other system/s. In rare cases (in case application grows extra huge) - one part of system from another.

Will your application "talk" with any other application?

If not and you are just building monolith website, free your mind and cut that SOA bullcrap. Otherwise you will end up with useless abstraction layer.

That is the only way you can apply 2nd approach because you can't decouple domain model completely without mapping it to something else.


In case there really is a need for SOA - we must encapsulate, hide from outer world our domain model. That means - there must be some kind of mapping from our model to DTOs.

Is there any article/tutorial that explains how to map AccountSummary DTO to FixedAccount/ SavingsAccount

Mapping itself isn't complex idea. Here's one simple way to map objects:

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);

This might seem ineffective. Object-to-object mappers like Automapper can help. Go through tutorial, it should be good enough to get you going. Idea ain't hard - you create Maps, tell Mapper about them on application start and then use Mapper to Map your objects by given configuration.


Also - think about mapping direction. Good object oriented code usually means that you either ask questions or tell object to do stuff. Objects shouldn't know about inner workings of other object responsibilities.

In analogy - it is bad for parents to complete their child homework because child won't learn anything and parent will be burdened with unnecessary work. Instead - parent should force child to work on his own.

Mapping AccountSummary directly to BankAccount and re-setting its state is like doing homework. There shouldn't be need for such a mapping. Instead - tell BankAccount to BankAccount.DoHomework(pencil, copybook, someStrongWords).


develop the business domain

You do not develop business domain. You develop domain model which is just a reflection of business domain, made to solve particular problems.

Jagged answered 29/2, 2012 at 22:45 Comment(2)
Thanks. Just one question. IF I don't use SOA why should I go for WCF? I can refer the projects directly, isn't it?Piranha
@Lijo True. WCF would be kind a unnecessary. Also - if you do go SOA, WCF is not mandatory. There are good alternatives like nservicebus.comJagged
L
2

For approach one, consider using a tool like AutoMapper rather than implementing the mapping manually. Could save you a great deal of pain. AutoMapper

Lipophilic answered 29/2, 2012 at 18:1 Comment(0)
C
2

Before you figure this part out, you need to decide what your clients are going to get from each service method call. Does the client need a FixedAccount/SavingsAccount, or does it really just need an AccountSummary?

If the method (like the one in your example) just returns AccountSummary, then one simple way to do this is to add a method to BankAccount that creates the AccountSummary. Then when you want to return something (no matter what type of account it is, but assuming your two accounts inherit from BankAccount), you just do this:

return someAccount.ToSummary()

Some people will tell you that it's not "pure" in the sense that you're BankAccount class now knows about your AccountSummary, but personally I've always found it easier to work with. If you don't like that, tools like AutoMapper can do this pretty effectively as well (as was mentioned in the other answers).

If you're returning some kind of derived class and not the actual class itself, there's no way to get around mapping it somewhere (if you use AutoMapper or write something yourself). The only way to avoid having to do any mapping is to return BankAccount itself, and that is not recommended for a service because internal changes to the class can affect the service. It's easy to remember that now, but it's also easy to forget about it in 3 years when another developer is doing maintenance. Mapping also only sends across the service things that you explicitly tell it to, so again it helps avoid mistakes that leak data.

The content of BankAccount.ToSummary() is pretty simple

public AccountSummary ToSummary()
{
    AccountSummary s = new AccountSummary();
    s.AccountNumber = AccountNumber();
    s.Balance = Balance()
    return s;
}
Cobber answered 3/3, 2012 at 12:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.