This project is read-only.

Composition Root

Jan 24, 2013 at 7:44 PM

What is the best practice for registering all dependencies in a multi-layer app where not all the projects are referenced in the initial project? 

The initial mvc project (UI) has a reference to a service.contracts project (for interfaces) and a service project (for implementation).

The service project (business logic) has a reference to a data.contracts project (for interfaces) and a data project (for implementation).

The data project  (repository and uow classes) has a reference to the Entity Framework.

In order to register all interface/concrete classes through the layers. research indicates options include creating a reference to all projects (layers) in the initial mvc project, but that leads to potentially direct calls to the data layer ~ ignoring the layer boundaries. Another option suggested was to create a new project 'CompositionRoot' that contains references to all other projects to provide the container all the types necessary to build the complete dependency hierarchy. If this is the way to go, is there sample code demonstrating this technique?

Is there a best practice for this situation? Is there a way to use the AppDomain to get loaded assemblies in Global.asax.cs Application_Start and extract the appropriate interface and concrete types that can be registered?

 


Jan 24, 2013 at 8:45 PM

The composition root will always be part of your start-up project. In some application types the start-up project will typically just be a thin wrapper -a bootstrapper- and it will call other code that is located in other assemblies. When building a command line program or Windows forms application, the .exe will be (or should be) very thin and the actual UI layer (Forms, Controls, etc) would typically be in one or multiple other assemblies. So in that sense the composition root is almost the complete start-up assembly.

In a web application this is often not feasible. It is very hard to extract the UI components (Controllers, Views, etc) out of the start-up project, or it is awkward at least. But besides, there is no need to. Although the composition root/bootstrapper is part of the web application, it's not part of the UI layer. They are architecturally two different pieces. Don't forget that a layer is a conceptual boundary, while a tier is a physical boundary. You decided to split your layers into physical artifacts (dlls) but from an architectural perspective there is no need to do this.

In theory, you can extract the composition root from the MVC project to its own project, but there's a problem with this. Since the MVC project is the startup project, it must call into this new 'bootstrapper' project to trigger the initialization. This bootstrapper project on the other hand, must know about the types in the MVC project to register it. This creates a circular reference on assembly level and Visual Studio does not allow this; for good reason.

You can solve this by using reflection, but this will only practically work for types that you can batch register. Controller types for instance can be batch-registered using the RegisterMvcControllers() extension method. In that case you will need to dynamically load the MVC project assembly (you can do this with the BuildManager.GetReferencedAssemblies method if you wish). When you defined some UI/MVC specific helper classes in the MVC project that need to be injected into the controller, you probably want to do this registration using static typing (using container.Register<TService, TImplementation>() for instance). It is very easy for the DI configuration to become brittle when there is only reflection to do the registration.

My general advice is to leave the complete composition root in the MVC project. This does mean that the MVC project itself has a dependency on an assembly that contains types that should not be referenced directly by Controllers and such. But if assembly references are your only way to protect your architectural boundaries.... in that case you have a problem. This will never be enough to ensure your architectural rules are complied with. The most rules can't be verified using assembly references and you'll need some other mechanism to do so.  There are tools out there such as NDepend that can help you with that, but more importantly, as an architect or team lead: do code reviews. Do code reviews and make sure the team knows and understands why these rules are important. Explain why it is important for a controller to not directly depend on an EntitiyFrameworkRepository. Developers will understand. And if they don't, you might have other problems to solve first.

This doesn't mean though that you can't extract parts of the composition root to a 'bootstrapper' assembly. This starts to get interesting when you have multiple applications (both a Web Service and a Web App for instance) that use the same business layer. In that case you can place the part of the DI configuration that wires the BL types (and types in assemblies below) together in its own project. In that case all application projects will still have their own composition root, but this will be much smaller, and will only contain the configuration that is unique to that application. Configuring MVC Controllers in a Windows Service application for instance makes no sense.

Simple Injector has -like most DI containers- a feature to split the composition root over projects and load them dynamically. Simple Injector calls them "packages". Personally I find this feature not very useful in most common scenarios. I rather define a static public Bootstrap(Container container) method in the referenced assembly and call it directly from the composition root of the application (as shown here). When the start-up project has a static assembly reference to the other projects, using a static Bootstrap method is the easiest and most reliable way to so.

I hope this helps.

Marked as answer by dot_NET_Junkie on 11/4/2013 at 2:05 AM