This would be behind a spoiler tag if I could get the markdown to work. Sorry.
As soon as I typed in "circular dependency", I got a ton of suggested results. Such as:
- How to handle “circular dependency” in dependency injection
- How to solve circular dependency
- Is circular Dependency Injection a good practice?
- Circular dependencies: Recursive grammar parser (e.g. json) (which, ironically, references the first three)
- Circular dependency and object creation when attempting DDD
I've read through those, and others. I still don't know how to solve my problem, thus this question:
Ok, real question.
The "typical" method of dependency injection for a data access layer goes something like this:
- Create an interface for your persistence layer within your domain layer.
- Have your domain services accept that interface in their constructors.
- Make sure your persistence layer implements that interface. This implies that the persistence layer depends on the domain layer, and all is good.
- Your client layer has references to the domain layer and to the persistence layer.
- Your client layer instantiates the persistence object and injects it into the domain services. This is typically done with a
using
clause.
For example:
// Simplified...
using (var p = new PersistenceThing ()) {
var s = new ServiceThing (p);
}
... and if you have multiple layers...
using (var p = new PersistenceThing ()) {
using (var s1 = new LowerLayerThing (p)) {
using (var s2 = new HigherLayerThing (s1)) {
// How deep does the rabbit hole go before you can actually do anything?
}
}
}
I have a valid need to move the creation of these service objects into factories. (The reasons are long, involving separation into separate tiers). That changes my project layout a little.
Going from the top down:
- I have a client project.
- Below that, I have an "upper layer interface" project that contains the service contract for the layer and the factory for the layer. The client project need only reference this "upper layer interface" project.
- Next, I have an "upper layer implementation" layer. This layer references the "upper layer interface" project and the "lower layer interface" project.
- Then there's a "lower layer interface" project containing the service contract and factory. It doesn't reference anything.
- Then a "lower layer implementation" layer. It references the "lower layer interface" project and... and...
And then I get to the persistence layer and it all breaks down.
I need to have a factory to handle the instantiation of my persistence layer. The lower service layer needs to have or reference the persistence interface because that's what it's working against. The factory needs to have or reference that same interface so that it can expose the proper method signature. Easy enough: the "persistence interface" project references the "lower service" project. But the "lower service" project needs to have access to the factory so that it can get an instantiation of the persistence layer.
My first thought was to move the interface into the "persistence interface" project, but it still needs a reference to the "lower service" project because it references all of the domain object types. My second thought was to move the factory into the "lower service" project, but it needs references to the "persistence implementation" layer so that it has something to instantiate. But the "persistence implementation" layer would still need a reference to the "lower domain" layer so that I can implement the interface.