145

(Related to this question, EF4: Why does proxy creation have to be enabled when lazy loading is enabled?).

I'm new to DI, so bear with me. I understand that the container is in charge of instantiating all of my registered types but in order to do so it requires a reference to all of the DLLs in my solution and their references.

If I weren't using a DI container, I wouldn't have to reference the EntityFramework library in my MVC3 app, only my business layer, which would reference my DAL/Repo layer.

I know that at the end of the day all DLLs are included in the bin folder but my problem is having to reference it explicitly via "add reference" in VS in order to be able to publish a WAP with all necessary files.

Steven
  • 166,672
  • 24
  • 332
  • 435
diegohb
  • 1,857
  • 2
  • 16
  • 34
  • 1
    [This excerpt](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/) from the book [Dependency Injection in .NET, second edition](https://manning.com/seemann2/) is a more elaborate version of the answers of both Mark and myself. It describes in detail the concept of the *Composition Root* and why letting the startup path of the application depend on every other module is actually a good thing. – Steven May 11 '18 at 21:52
  • I read through that excerpt link and chapter 1, I'll be buying the book as I've really enjoyed the analogies and simple explanations to the complex matter of DI. I think you should suggest a new answer, answer clearly "you don't have to reference all layers/assemblies in entry logical layer unless it is also your composition root," link to the excerpt, and post the image Figure 3, from the excerpt. – diegohb May 12 '18 at 07:01

4 Answers4

211

If I wasn't using a DI container, I wouldn't have to reference EntityFramework library in my MVC3 app, only my business layer which would reference my DAL/Repo layer.

Yes, that's exactly the situation DI works so hard to avoid :)

With tightly coupled code, each library may only have a few references, but these again have other references, creating a deep graph of dependencies, like this:

Deep Graph

Because the dependency graph is deep, it means that most libraries drag along a lot of other dependencies - e.g. in the diagram, Library C drags along Library H, Library E, Library J, Library M, Library K and Library N. This makes it harder to reuse each library independently from the rest - for example in unit testing.

However, in a loosely coupled application, by moving all the references to the Composition Root, the dependency graph is severely flattened:

Shallow Graph

As illustrated by the green color, it's now possible to reuse Library C without dragging along any unwanted dependencies.

However, all that said, with many DI Containers, you don't have to add hard references to all required libraries. Instead, you can use late binding either in the form of convention-based assembly-scanning (preferred) or XML configuration.

When you do that, however, you must remember to copy the assemblies to the application's bin folder, because that no longer happens automatically. Personally, I rarely find it worth that extra effort.

A more elaborate version of this answer can be found in this excerpt from my book Dependency Injection, Principles, Practices, Patterns.

Steven
  • 166,672
  • 24
  • 332
  • 435
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 4
    Thanks so much, this now makes perfect sense.. i needed to know if this was by design. As far as enforcing the correct use of dependencies, I had implemented a seperate project with my DI bootstrapper like Steven mentioned below where I reference the rest of the libraries. This project is refereced by the entry point app and at the end of the full build, this causes all necessary dlls to be in the bin folder. thanks! – diegohb Mar 01 '12 at 00:06
  • 2
    @Mark Seemann Is this question/answer specific to Microsoft? I would like to know if this idea of moving all dependencies to the "entry point of the application" makes sense to a Java EE/Spring project using Maven… thanks! – Grégoire C Nov 27 '13 at 09:18
  • 6
    This answer applies beyond .NET. You may want to refer to Robert C. Martin's *Principles of Package Design* chapter in e.g. [Agile Software Development, Principles, Patterns, and Practices](http://amzn.to/195wrPB) – Mark Seemann Nov 27 '13 at 09:49
  • 1
    Does the composition root method make the process similar to the Service Locator pattern? I may be misunderstanding something. If i have a hard reference to all assemblies, doesn't it violate the Liskov sub principle since i now have to make a change and rebuild the composition root every time a new library is made? – Andy Danger Gagne Jul 03 '14 at 19:06
  • 7
    @AndyDangerGagne The Composition Root is a DI pattern - the [opposite of Service Locator](http://www.infoq.com/articles/Succeeding-Dependency-Injection). From the perspective of the Composition Root, none of types are polymorphic; the Composition Root sees all types as concrete types, and thus, the Liskov Substitution Principle doesn't apply to it. – Mark Seemann Jul 04 '14 at 07:27
  • 2
    Took me quite some time to find this question and answer. Even though there's a lot of reading about what a Composition Root is, I feel there's less articles describing pros/cons of having the Composition Root within the actual application, or in a separate assembly. It wasn't obvious to me that manually copying the assemblies (when using late-binding) is "the way to go", but this answer clarified that point! – Jim Aho Aug 30 '14 at 11:26
  • 2
    @MarkSeemann When using the CompositionRoot approach how do you tackle the references between libraries? For example Library J needs and interfaced implementation from library N. In which package would you put this interface? Would you make an dedicated packaged like "Common Interfaces" and all Libraries and the Compostion Root would have a reference to it? Or maybe you would even make an "Inteface package" for each library (supose the libraries are implementing distinct functionalities)? – Pellared Oct 08 '14 at 05:36
  • 4
    As a general rule, interfaces should be defined by the clients using them ([APP, ch. 11](http://amzn.to/19W4JHk)), so if Library J needs an interface, it should be defined in Library J. That's a corollary of the Dependency Inversion Principle. – Mark Seemann Oct 08 '14 at 06:38
  • 1
    @MarkSeemann Or use the [Seperated Interface pattern](http://example.com) but then the references to packages are inverted (this looks almost looks for me like [Depedency Inversion Principle](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod) but on the packaging level). – Pellared Oct 08 '14 at 06:42
  • 1
    @Pellared FWIW, [APP](http://amzn.to/19W4JHk) also contains a section on package management principles... – Mark Seemann Oct 08 '14 at 10:01
  • 1
    This is a great answer! I have one more question. When we use Composition Root pattern all the libraries still need to know interfaces of other libraries. Where to we put those interfaces? The only idea I have is to create another DLL with interfaces only and all Libraries will reference it directly. Is that OK or you know any better solution? – Michał Jankowski Nov 19 '14 at 09:56
  • 2
    @MichałJankowski If you're already referencing all libraries, you should also be referencing the libraries that define the interfaces. In any case, according to SOLID, interfaces are owned by the clients, so should typically be defined together with (in the same library as) the clients that consume them. Read more in [Agile PPP](http://amzn.to/19W4JHk). – Mark Seemann Nov 19 '14 at 16:50
  • 2
    @MarkSeemann Reading this makes me fell that the illustrations are a bit misleading (which some of the comments also indicates). The arrows in the illustrations are referred to as references between the libraries which, in the .NET world, is easily interpreted as a reference between projects in Visual Studio. If that is the case then the second illustration is way to simple. Given the example of Library C being easier to reuse – Terje Nov 28 '14 at 14:46
  • 2
    but what about Library H? From the illustration is seems that it too is easy to reuse, but as indicated Library C should define the Interface it needs so H now has a reference to C in order to implement its interface so that it can be injected into C. This is not show in the second illustration. On the other hand if the arrows in the illustration indicates "who new's up who" then it makes much more sense, but the text accompanying the illustrations indicate the first story. – Terje Nov 28 '14 at 14:54
  • 2
    @Terje The illustrations are there to make a point. You don't have to flatten the dependency hierarchy entirely, as illustrated. In the second diagram, there's only a single layer of dependency. In practice, for the reasons you outline, you may need two layers. The point is that you should favour flat dependency graphs over deep dependency graphs. – Mark Seemann Apr 29 '15 at 08:24
  • 3
    @Terje BTW, your question assumes that interfaces *must* be defined in other custom libraries, which doesn't *have* to be the case. For instance, in .NET, I often use `IEnumerable` or `IObserver` for dependencies. These are defined in the BCL, so automatically already available to all consumers and implementers. – Mark Seemann Apr 29 '15 at 08:25
71

If I wasn't using an DI container, I wouldn't have to reference EntityFramework library in my MVC3 app

Even when using a DI container, you don't have to let your MVC3 project reference Entity Framework, but you (implicitly) choose to do this by implementing the Composition Root (the startup path where you compose your object graphs) inside your MVC3 project. If you are very strict about protecting your architectural boundaries using assemblies, you can move your presentation logic to a different project.

When you move all MVC related logic (controllers, etc) from the startup project to a class library, it allows this presentation layer assembly to stay disconnected from the rest of the application. Your web application project itself will become a very thin shell with the required startup logic. The web application project will be the Composition Root that references all other assemblies.

Extracting the presentation logic to a class library can complicate things when working with MVC. It will be harder to wire everything up, since controllers are not in the startup project (while views, images, CSS files, must likely stay in the startup project). This is probably doable but will take more time to set up.

Because of the downsides I generally advice to just keep the Composition Root in the web project. Many developers don’t want their MVC assembly to depend on the DAL assembly, but that should not be a problem. Don't forget that 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. It's very well possible (and common) to have multiple layers in the same assembly.

In this case you'll end up having the Composition Root (layer) and the Presentation Layer in the same web application project (thus in the same assembly). And even though that assembly references the assembly containing the DAL, the Presentation Layer still does not reference the DAL—this is a big distinction.

Of course, when you do this, you're losing the ability for the compiler to check this architectural rule at compile time. But most architectural rules actually can't be checked by the compiler. In case you're afraid your team won't follow the architectural rules, I'd advise introducing code reviews, which is an important practice to increase code quality, consistency and improve the skills of a team. You can also use tools like NDepend (which is commercial), which help you verifying your architectural rules. When you integrate NDepend with your build process, it can warn you when somebody checked code in that violates such architectural rule.

You can read a more elaborate discussion on how the Composition Root works in chapter 4 of my book Dependency Injection, Principles, Practices, Patterns.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • A seperate project for bootstrapping was my solution since we don't have ndepend and I've never used it before. I will look into it though since it sounds like a better way to accomplish what I'm trying to do when there will be only 1 end application. – diegohb Mar 01 '12 at 00:12
  • 1
    The last paragraph is a great one and is starting to help me change my mind on how strict I am with keeping layers in separate assemblies. Having two or more logical layers in one assembly is actually fine if you employ other processes around the writing of code (such as code reviews) to ensure there is no referencing of DAL classes in your UI code and vica versa. – BenM Sep 16 '15 at 08:00
7

If I wasn't using an DI container, I wouldn't have to reference EntityFramework library in my MVC3 app, only my business layer which would reference my DAL/Repo layer.

You can create a seperate project called "DependencyResolver". In this project you have to reference all your libraries.

Now the UI Layer doesn't need NHibernate/EF or any other not UI relevant library except of Castle Windsor to be referenced.

If you want to hide Castle Windsor and DependencyResolver from your UI layer you could write an HttpModule which calls the IoC registry stuff.

I have only an example for StructureMap:

public class DependencyRegistrarModule : IHttpModule
{
    private static bool _dependenciesRegistered;
    private static readonly object Lock = new object();

    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, args) => EnsureDependenciesRegistered();
    }

    public void Dispose() { }

    private static void EnsureDependenciesRegistered()
    {
        if (!_dependenciesRegistered)
        {
            lock (Lock)
            {
                if (!_dependenciesRegistered)
                {
                    ObjectFactory.ResetDefaults();

                    // Register all you dependencies here
                    ObjectFactory.Initialize(x => x.AddRegistry(new DependencyRegistry()));

                    new InitiailizeDefaultFactories().Configure();
                    _dependenciesRegistered = true;
                }
            }
        }
    }
}

public class InitiailizeDefaultFactories
{
    public void Configure()
    {
        StructureMapControllerFactory.GetController = type => ObjectFactory.GetInstance(type);
          ...
    }
 }

The DefaultControllerFactory doesn't use the IoC container directly, but it delegates to IoC container methods.

public class StructureMapControllerFactory : DefaultControllerFactory
{
    public static Func<Type, object> GetController = type =>
    {
        throw new  InvalidOperationException("The dependency callback for the StructureMapControllerFactory is not configured!");
    };

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return base.GetControllerInstance(requestContext, controllerType);
        }
        return GetController(controllerType) as Controller;
    }
}

The GetController delegate is set in a StructureMap Registry (in Windsor it should be an Installer).

Rookian
  • 19,841
  • 28
  • 110
  • 180
  • 1
    i like this even better than what I ended up doing, modules are great. so then where would I make the call to Container.Dispose() ? ApplicationEnd or EndRequest event within the module ... ? – diegohb Mar 01 '12 at 00:23
  • What an odd way of doing things. Why do you want to do this instead of just calling EnsureDependenciesRegistered from the Application_Start of the Global.asax? – Steven Mar 01 '12 at 05:15
  • 1
    @Steven Because the Global.asax is in your MVC UI Layer. The HttpModule would be in the DependencyResolver Project. – Rookian Mar 01 '12 at 10:10
  • So you still have a reference to your DependencyResolver project, but now implicitly through the webl.config instead of using a project reference. What's the use of that? – Steven Mar 01 '12 at 11:02
  • 2
    The little benefit is that nobody can use the IoC container in the UI. I.e. nobody is able to use the IoC Container as a service locator in the UI. – Rookian Mar 01 '12 at 11:39
  • 2
    Also, it disallows developers from accidentally using the DAL code in the UI layer since there is no hard reference to the assembly in the UI. – diegohb Mar 01 '12 at 13:41
  • 1
    I've figured out how to do the same thing using Bootstrapper's generic registration API. My UI project references Bootstrapper, the dependency resolution project where I wire up my registrations, and projects in my Core (for the interfaces) but nothing else, not even my DI Framework (SimpleInjector). I am using OutputTo nuget to copy dlls to the bin folder. – diegohb Sep 27 '13 at 02:10
1
  • There is a dependency : if an object instantiate another object.
  • There is no dependency : if an object expects an abstraction (contructor injection, method injection ...)
  • Assembly References (referencing dll, webservices..) are independant from the dependency concept, because to resolve an abstraction and be able to compile the code, the layer must reference it.
Scott Baker
  • 10,013
  • 17
  • 56
  • 102
riadh gomri
  • 869
  • 1
  • 15
  • 21