What design approach allows a presentation layer to optionally depend on local DLL calls or WCF Service calls based on configuration?
I am designing an internal web application that will have 3 layers:
- Presentation (MVC)
- Service & Workflow
- Data Access / Persistent Storage
Initially the application will run in a simple 2-tier environment. However, at some point I want it to be able to easily expand/scale to 3 tiers, one for each layer.
I could simply use WCF services for the Service layer but I have found considerable overhead to calls, even us开发者_运维问答ing named pipes (IIS hosted). I would prefer to have a solution that can be configured to use local DLL calls in the 2-tier style but use WCF calls in the 3 tier style.
I believe DI works well here but I'm looking for someone who has done this to explain any potential pitfalls with this method.
i think you've nailed it with the DI suggestion. also the repository pattern will help you here.
firstly, write an interface which will wrap all the calls to the as-yet-undefined third layer. this will be our contract to code against (do not confuse this with WCF data contracts, they will exist separately.
//use a more descriptive name of course
public interface IThirdLayer {
void SomeRepositoryMethod(SomeArg arg);
}
then write two concrete implementations of this interface, one for your local repository (perhaps SQL calls), one for the remote repository (perhaps using a service reference or the ChannelFactory
class). these classes will encapsulate all your logic for the third layer,.
In any class which wishes to make use of this layer, simply pass an implementation of IThirdLayer
:
public class SomeBusinessLogicClass {
private readonly IThirdLayer _repository;
//constructor injection for the win!
public SomeBusinessLogicClass(IThirdLayer repository) {
_repository = repository;
}
public void SomeBusinessLogicMethod(SomeArgs arg) {
//example use of repository
_repository.SomeMethod(arg);
}
}
because we're coding against a contract (the interface IThirdLayer
), and supplying that contract via the constructor, our business logic layer does not need to aware of any details of the implementation of the third layer i.e. whether it be WCF, SQL, or even File-based.
you could also use your favourite dependency injection container to help you here, this will provide the configuration that you need. personally i use microsoft's Unity, but there are many options available so i won't post example configuration.
hope that's helpful.
edit: i forgot to quell your fears of pitfalls with this approach. other than having to write a few extra classes to achieve the abstraction you need, there are no other pitfalls really. this is the kind of pattern you can repeat over and over for all sorts of scenarios, not just this one. it is always good practice to code against an interface, even if there is only ever going to be one concrete implementation of said interface in your production code.
Why is this so? the reason is that you can easily switch implementation if you ever need to in future, and also because you will often have another implementation of said interface in your unit tests - whether it be a handwritten mock implementation, or an implementation dynamically generated by a mocking framework (i use Rhino Mocks). so another benefit of this approach is testability, in unit tests you supply test-specific implementations of your Repository's interface - meaning your business logic can be tested in isolation with no dependencies on concrete classes.
精彩评论