|
I had a super-duper vacation and now slowly trying to reply
bunch of emails piled up in my inbox. Just came across this question being
asked quite frequently and thought it would be nice to share my answer here.
Question:
1.
I don’t want to have any business or data logic
implementation within my service
2.
I want to implement my business or data logic
within a separate component taking advantage of .NET specific data types, for
example DataSet or DataTable
Since any service communicates with xml-messages and
my business or data logic component communicates with .NET data types, I
thought of a “MessageBroker” component between the service and the logic
component. The “MessageBroker” class implements the IxxxServicePort interface
created by the WSCF-tool.
Now I ran into the following problems. The problem is
that my service's (WebMethod) method receives a message within the services
namespace and I want to pass that message on to my “MessageBroker’s” public
method that implements the same message class within the “MessageBroker”
namespace. The compiler cannot convert between the message classes since they
are in different namespaces. Adding a reference from the “MessageBroker”
component to the service would end up in a circular dependency.
The question is:
What is your recommendation/best practice when it
comes to separating the service implementation from the business or data logic?
Or am I of the chart again?
Answer
You are running into a basic
mapping problem here. However, I do not think using the Broker pattern is the ideal solution because Broker pattern is for encapsulating the communication details.
Adapter pattern sounds more elegant
in your situation. It can help you to change one interface to support
another interface. This way you can implement an adapter to change your BusinessLogic
interface to suit the Service interface. Let’s consider the following
sample. Suppose we have a business logic (BL) component which updates a list of
addresses for a given customer. So our BL class may look like:
public class AddressManager
{
void AddNewAddresses(int customerId, Dataset addresses)
{
//…
}
}
And the corresponding service
interface for this may look like:
public interface IAddressService
{
void AddNewAddresses(AddNewAddressRequest request);
}
Now we can not simply pass the AddNewAddressRequest
to AddressManager.AddNewAddresses method. Therefore we create an AddressManagerAdaptor
to do that work for us.
public class AddressManagerAdapter : IAddressService
{
private AddressManager addressManager = new AddressManager();
public void AddNewAddresses(AddNewAddressRequest request)
{
Dataset addresses = new Dataset();
int customerId;
// Read the addresses and customer id from the request and assign them to
// addresses and customerId respectively.
// Now invoke the method in the business logic class.
addressManager.AddNewAddresses(customerId, addresses);
}
}
As you can see in the sample code,
the AddressManagerAdapter simply implements the service interface and
routes the calls to AddressManager (BL) appropriately.
You can either keep your adaptors
in your service assembly or you can have a separate assembly for that. This
decision is totally up to you and it will not make any difference. BTW: you may
want to think about the Factory pattern to hide the details of instantiating
the adapters.
Hope this helps.
|