Reputation: 81
I have what I hope is a basic question regarding dependency injection in an MVC app that I haven't been able to find a satisfactory answer to. My app consists of an MVC 3 project, a service layer class library (SL) and a data access class library (DAL). Both SL and DAL contain their respective interfaces and implementations. The MVC project references both SL and DAL projects. The MVC project will create an implementation of DAL and inject it into the SL constructor which accepts the DAL interface.
The concern I have is in order for SL to accept the DAL interface as a parameter it also needs a reference to the DAL project (where the interface happens to live but also the implementation), which seems to violate DI as now both the MVC and SL projects need references to the DAL assembly.
Long story short, would it make more sense to move the DAL interface into its own project so that the SL only needs to reference the interface project and not the implementation project? MVC project would obviously need to reference both interface and implementation projects and DAL would need to reference the interface project as well. This seems a cleaner way of doing things even though it adds another project to my solution, which doesn't bother me that much. I've also seen suggestions to store the DAL interface inside the SL and have DAL reference SL but that doesn't seem right to me. Any insight or suggestions are appreciated. Thanks!
Upvotes: 3
Views: 4112
Reputation: 112352
True components must have their interface and their implementation(s) in separate assemblies.
This allows you to load an appropriate implementation dynamically like an add-in. Often it is also the only way to avoid circular references. As an example the DAL needs to know the model (business class) and the model might want to lazy load a dependent model through a DAL call, what creates a circular reference (.NET forbids circular assembly references). If the interfaces are in separate assemblies, both the DAL and Model assemblies have references to both of the interface assemblies and get the dependency injected through the constructor.
// Assembly: Model contracts
public interface IModelA
{
IModelB ModelB { get; }
...
}
public interface IModelB
{
...
}
public interface IModelFactory
{
IModelA CreateModelA();
IModelB CreateModelB();
}
// Assembly: DAL contracts, references Model contracts
public interface IDAL
{
IModelA LoadA(int id);
IModelB LoadB(int id);
}
// Assembly: Model implementation, references Model and DAL contracts
public class ModelA : IModelA
{
private IDAL _dal;
public ModelA (IDAL dal)
{
_dal = dal;
}
private IModelB _modelB;
public IModelB ModelB
{
get {
if (_modelB == null) {
_modelB = _dal.LoadB(5);
}
return _modelB;
}
}
}
// Assembly: DAL implementation, references Model and DAL contracts
public class DAL : IDAL
{
private IModelFactory _modelFactory;
public DAL(IModelFactory _modelFactory)
{
_modelFactory = modelFactory;
}
public IModelA LoadA(int id)
{
IModelA modelA = _modelFactory.CreateModelA();
// fill modelA with data from database
return modelA;
}
public IModelB LoadB(int id)
{
IModelB modelB = _modelFactory.CreateModelB();
// fill modelB with data from database
return modelB;
}
}
Upvotes: 2
Reputation: 172646
Referencing assemblies with concrete types in them can be a problem, but it depends on what you are trying to achieve. By letting services only depend upon abstractions, you achieve loosely coupled code. This improves maintainability.
Letting your BL assembly only reference an assembly that contains abstractions (and not the implementations) allows you to deploy parts of your software independently. Say for instance that you want to deploy your software to different customers and you have several flavors of your DA layer, but don't want to deploy all DA flavors to all customers (for instance because they need to pay per DA layer, or perhaps you try to protect your intellectual property).
So if separation is not a concern for deployment, you don't have to create separate assemblies.
Upvotes: 1
Reputation: 1846
As the rule says it's fine as far as you depend on interfaces not concrete implementations. So what you could do is to have your interfaces in separate assemblies and refer them where ever you want.
Upvotes: 1
Reputation: 8503
Take a look at the onion architecture:
http://jeffreypalermo.com/blog/the-onion-architecture-part-1/
http://jeffreypalermo.com/blog/the-onion-architecture-part-2/
http://jeffreypalermo.com/blog/the-onion-architecture-part-3/
It is perfectly fine to have the UI assembly having references to all the service and business logic assemblies. The service layer should obviously reference the infrastructure assemblies that should not be dependent on anything higher level.
Upvotes: 5