tags:

views:

682

answers:

10

I am just starting out with DI & unit testing and have hit a snag which I am sure is a no brainer for those more experienced devs :

I have a class called MessageManager which receives data and saves it to a db. Within the same assembly (project in Visual Studio) I have created a repository interface with all the methods needed to access the db. The concrete implementation of this interface is in a separate assembly called DataAccess.

So DataAccess needs a project reference to MessageManager to know about the repository interface. And MessageManager needs a project reference to DataAccess so that the client of MessageManager can inject a concrete implementation of the repository interface. This is of courser not allowed

I could move the interface into the data access assembly but I believe the repository interface is meant to reside in the same assembly as the client that uses it

So what have I done wrong?

+1  A: 

I think you should move the repository interface over to the DataAccess assembly. Then DataAccess has no need to reference MessageManager anymore.

However, it remains hard to say since I know next to nothing about your architecture...

Thomas
+2  A: 

You only have two choices: add an assembly to hold the interface or move the interface into the DataAccess assembly. Even if you're developing an architecture where the DataAccess class may someday be replaced by another implementor (even in another assembly) of the repository interface, there's no reason to exclude it from the DataAccess assembly.

Craig Eddy
+1  A: 

You should separate your interface out of either assembly. Putting the interface along with the consumer or the implementor defeats the purpose of having the interface.

The purpose of the interface is to allow you to inject any object that implements that interface, whether or not it's the same assembly that your DataAccess object belongs to. On the other hand you need to allow MessageManager to consume that interface without the need to consume any concrete implementation.

Put your interface in another project, and problem is solved.

Jon Limjap
+2  A: 

Frequently you can solve circular reference issues by using setter injection instead of constructor injection.

In pseudo-code:

Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);
A: 

Hi - thanks for the replies. I can see that your suggestion would work but it seems that I would have an awful lot of assemblies if I applied this to a typical project. And from reading Bob Martin's Patterns and Practices book it seems to suggest that the interface should reside with the client that uses it UNTIL another client needs to use that interface

Christo Fur
A: 

You could leave the structure as you currently have it (without the dependency from MessageManager to DataAccess that causes the problem) and then have MessageManager dynamically load the concrete implementation required at runtime using the System.Reflection.Assembly class.

Simon Fox
A: 

using reflection seems a bit of a hack. I am sure there is a simple answer to this and it is obviously something that the TDD crowd must do all the time. I'd like to hear how people get around this. I'm sure it is a very common scenario

Christo Fur
+1  A: 

Are you using an Inversion of Control Container? If so, the answer is simple.

Assembly A contains:

  • MessageManager
  • IRepository
  • ContainerA (add MessageManager)

Assembly B contains (and ref's AssemblyA):

  • Repository implements IRepository
  • ContainerB extends ContainerA (add Repository)

Assembly C (or B) would start the app/ask the container for MessageManager which would know how to resolve MessageManager and the IRepository.

aaronjensen
I'm not using an IoC container but I can now see that would be the way to go. It saves me having to create lots of new assemblies and I have one place to inject all my dependancies from. it is all starting to fall into place now - thanks
Christo Fur
A: 

Dependency inversion is in play:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

The abstraction that the classes in the DatAccess assembly depend upon needs to be in a separate assembly from the DataAccess classes and the concrete implementation of that abstration (MessageManager).

Yes that is more assemblies. Personally that's not a big deal for me. I don't see a big downside in extra assemblies.

Hamish Smith
A: 

thanks for the replies. It seems to me that the IoC container is the way to go. And where this is not possible then create a new assembly to to place the interface in

Christo Fur