1

Say I have BusinessService & domain logic as part of MyProj.MiddleTier csproj which connects to MyProj.DAL DataRepository via interface IDataRepository.

I am using IOC unity container to build my dependency object graph. Composition root and BusinessService are all part of MyProj.MiddleTier (BusinessService is WCF based service consumed from WEB server and I have overridden ConfigureContainer method to build object dependency graph using my own serviceHostFactory)

I would like to understand shouldn’t IDataRepository be part of separate csproj (assembly) ? In fact shouldn’t be composition root itself be separate project/assembly holding reference of all assemblies ? If not, then I feel whole purpose of DI is defeated. Why ? Because if MyProj.MiddleTier has hard dependency reference of MyProj.DAL then I cannot simply switch to another persistence technology tomorrow without recompiling MyProj.MiddleTier. Had been MyProj.DAL just referenced that IDataRepository in separate assembly, it would have required to just deploy MyProj.DAL dll.

Also by not having it as part of separate assembly, developers can accidentally directly reference to classes and implementation of DataRepository in Business/Domain logic. Is this well known trade off ? If yes, then what are merits ?

In stack overflow I see mix of response :

This post on SO says actually there is no harm in doing so however another post says its good to have separate assembly.

Irrespective of above mixed SO answers, I was holding good belief on my thought process until I bumped upon similar text from famous book “Dependency Injection in .Net”. Here example taken is of ASP.NET MVC project where UI layer and composition root for building object graphs are part of same assembly.

However author also provided some explanation for this :

Don’t be misled into thinking that the Composition Root is part of your UI layer. Even if you place the Composition Root in the same assembly as your UI layer, the Composition Root isn’t part of that layer. Assemblies are a deployment artifact: you split code into multiple assemblies to allow code to be deployed separately. An architectural layer, on the other hand, is a logical artifact: you can group multiple logical artifacts in a single deployment artifact. Even though the assembly that holds both the Composition Root and the UI layer depends on all other modules in the system, the UI layer itself doesn’t

I think the core of my confusion is because of not understanding point around deployment artifact and logical artifact. I would be great if someone can help me understand this better.

2 Answers 2

4

I feel whole purpose of DI is defeated. Why ? Because if MyProj.MiddleTier has hard dependency reference of MyProj.DAL then I cannot simply switch to another persistence technology tomorrow without recompiling MyProj.MiddleTier.

No it's not defeated. Goal of DI is to abstract away dependencies, reduce coupling and facilitate testing with mocks or stubs. Switching implementations especially without recompilation is a more rare use case. Also chances are that another persistence technology is so different that it may require modifications of the interface itself.

developers can accidentally directly reference to classes and implementation of DataRepository in Business/Domain logic.

There are dependency diagrams in Visual Studio that can be used to enforce relations between architectural layers. Put repo implementation into a separate namespace and add rule that this namespace can't be consumed by business namespace. In fact it is a good idea to use this tool whether there is one assembly or few.

Also, depending where your composition root code resides, it could be possible to mark implementation classes as internal for extra protection.

To summarize, it is definitely OK to have multiple logical layers within one unit of deployment i.e. assembly. Split units of deployments when it is needed (e.g part of assembly is slow to recompile, or should be packaged and reused in different solution etc.)

2
  • 2
    Most of the time DI used only for mocks or stubs in test assemblies -- Really? I thought DI was used to decouple classes from each other, to abstract the dependencies. Sep 3, 2019 at 22:57
  • Yes it'd be more correct to say that DI helps to abstract away dependencies. Which is in turn used mostly to facilitate testing (maybe it's just me?) and reduce coupling. Fixed wording
    – KolA
    Sep 4, 2019 at 15:42
3

I think what you're experiencing is a sort of "dependency leak", where the "implementation details" of one layer is leaking into another layer. EntityFramework is notorious for forcing this onto unsuspecting developers. Basically the best way to avoid this is the following:

  • MyProj.DAL is made up entirely of classes that only take DTOs (or plain classes) and it internally transforms to and from your entity types
  • The outside world communicates with MyProj.DAL explicitly through interfaces that only accept DTOs for both input and output
  • BusinessService happens entirely on DTOs (you can create as many helper DTOs as you need to perform validations and business rules - this will lead to lots of transformations)
  • IDataRepository can be part of the MyProj.DAL or be a separate assembly depending on it

So because of the way the framework is designed, it is very difficult to successfully pull this off. If you go this route, you will definitely lose most of the benefits of something like EF. But, on the other hand, like you said, it will be too easy for someone to accidentally depend on some assembly they should not.

We've done this exact thing before and the biggest challenge for us was that 90% of our code base became mapping one type to another (transformations). As each service layer has it's own unique DTO and that causes you to write a lot of code that simply copies one type to another. This was all due to the fact that we used EF heavily and we could not ditch EF. If your project is using direct SQL or something simpler than EF, then it will be much easier to accomplish this. But if you're using EF and you want to have the powerful EF features, it will be very difficult. The good news is there are other ORMs that are much simpler than EF and they don't leak their implementation details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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