0

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:

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:

  1. Create an interface for your persistence layer within your domain layer.
  2. Have your domain services accept that interface in their constructors.
  3. Make sure your persistence layer implements that interface. This implies that the persistence layer depends on the domain layer, and all is good.
  4. Your client layer has references to the domain layer and to the persistence layer.
  5. 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.

  • 2
    Why don't you just put all of the relevant interfaces into a single project, and reference that project or dll everywhere? – Robert Harvey Aug 10 '16 at 21:18
  • The persistence interface references my domain entities. On all of the other layers, I'm using DTOs that are in the "interface" projects. – J Fenter Aug 10 '16 at 21:47
  • 2
    OK. Well, the way I usually break circular dependencies is by putting the common dependencies in a common place, so that there is only a single reference to them. – Robert Harvey Aug 10 '16 at 21:57
  • 3
    Can you please draw a diagram of your design instead of describing it? UML exists for a good reason. But from what I can imagine from your description your whole design doesn't make much sense. Especially with your focus on factories. – Euphoric Aug 11 '16 at 5:56
2

That's not how layered (or tiered) architecture works. Specifically: each layer only has knowledge of the layers directly below it and any required shared objects. Which contradicts items 4 and 5 in your list of how typical dependency injection works. Which is why you have a circular dependency problem.

In a three layer system consisting of client, domain and persistence layers: 1. The client layers "knows" about the domain layer through interfaces and shared data objects 2. The domain layer "knows" about the client layer interfaces (because it implements them) and the shared data objects the client requires 3. The domain layer also "knows" about the persistence layer interfaces and persistence shared data objects. 4. The persistence layer "knows" about the persistence layer interfaces (because it implements them) and persistence shared data objects

So you end up with five projects. A client project, a domain project, a persistence project, a project that is referenced by the client and the domain and a project that is referenced by domain and persistence. If you have a common data object that you want to reference in all layers, then that goes in another project.

Assuming this is a desktop application you will have one additional parent project that references everything but is only there to start up the app. In that project you can use something like Unity to do your actual injection.

  • Ouch, why the -1? – Old Fat Ned Aug 11 '16 at 11:00
  • 1
    I don't know but i can say this is wrong : each layer only has knowledge of the layers directly above and below. This is wrong, a layer is not supposed to be aware of the layer above him. All the layer are based of course on the model, though they can be separated using DTO but it's not always worth. – Walfrat Aug 11 '16 at 12:16
  • 1
    That's fair, I will edit my answer to reflect that. – Old Fat Ned Aug 11 '16 at 12:30
  • "The domain layer -knows- about the client layer interfaces" This is probably wrong. The domain layer should not have any knowledge of the client. The client knows about the domain as it interacts with it through it's public interfaces, but not the other way arround; That allows you to have several clients (ie web + api + CLI, etc) – istepaniuk Aug 21 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.