Dependency Resolution in Onion Architecture
Asked Answered
L

2

11

The Onion Architecture is a way of structuring applications to maintain separation of concern and loose coupling (example project at: http://onionarch.codeplex.com/). Dependency Injection/Resolution is a key aspect of this architecture, since it is used to tie all the layers together.

The above link contains an example application on how to structure an ASP.NET MVC using the Onion layering. I really like it, but most of these examples use Ninject (which we all know is pretty slow). I was wondering if someone could perhaps eloborate on how to integrate a different DI tool (like SimpleInjector, Unity or Autofac) into an Onion Project.

It is key that all layers only have 1 dependency (including the MVC project), namely the Core layer. Except for the Dependency Resolution layer, this layer can reference all the layers.

I'm having a hard time setting the MVC project as a startup project, using DI, and not including a reference to the DI tool in the MVC layer.

Loren answered 15/2, 2013 at 9:15 Comment(0)
M
16

Your question is

"how to integrate a different DI tool (like SimpleInjector, Unity or Autofac) into an Onion Project?"

I’m using StructureMap instead of Ninject, the way it’s integrated should be ok for any other DI framework.

As you said, only the Dependency Resolution Layer should reference all the other layers, it’s the outermost layer of your Onion Architecture. Well, to do so, I’ve created a project called BootStrapper. This is the only project where I reference StructureMap assemblies. In the App_Start folder of this project, I have a file named StructureMapMvc.cs which looks like this:

[assembly: WebActivator.PreApplicationStartMethod(typeof(XXXX.BootStrapper.App_Start.StructuremapMvc), "Start")]

namespace XXXX.BootStrapper.App_Start
{
    public static class StructuremapMvc
    {
        public static void Start()
        {
            IContainer container = IoC.Initialize();
            System.Web.Mvc.DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
            GlobalConfiguration.Configuration.DependencyResolver = new StructureMapHttpDependencyResolver(container);
            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
        }
    }
}

The interesting line is:

[assembly: WebActivator.PreApplicationStartMethod(typeof(XXXX.BootStrapper.App_Start.StructuremapMvc), "Start")]

According to the nugget package’s description:

WebActivator is a NuGet package that allows other packages to execute some startup code in web apps.

Pretty cool, huh? The last thing you have to put in place is to be sure that the BootStrapper project assembly will be pushed to the /bin folder of your web application (easy to set up using a post build action or OutputTo nugget package). This will avoid you to reference the BootStrapper project in your MVC project and break the Onion Architecture principle.

So, with all this in place, it adheres totally with the Composition Root Pattern and when your app will start, modules will be composed together.

Hope this helps!

Mindy answered 4/3, 2013 at 11:1 Comment(8)
I have the DependencyResolution in a different project, but when I copy the DLL to the /bin of the UI project by using a Post-build event, it doesn't wire up (breakpoints aren't hit while debugging etc.). However, if I add a reference in the UI project to the DependencyResolution project, it does wire up. Any idea why?Viviparous
Did you copy all the DLL's that your UI project needs to work properly? Think about copying the .pdb files as well if you want to be able to debug.Mindy
Ah I see, forgot some. Why is it exactly better then a project reference?Viviparous
Because in a "pure" onion architecture, direction of dependency between layers is toward the center. As the Bootsrapper project is in the outermost layer, it should not be referenced by any other projects.Mindy
Is it fine if I reference BootStrapper from MVC(UI) App_Start or BootStrapper is going to call MVC(UI)?Selig
@user960567 one thing about Onion architecture is that references are made towards the center. If your MVC reference your Bootstrapper layer, than it breaks that rule (as the DI layer is the outermost layer of your app)Mindy
@MaxS - Betclic I would like to complicate it a bit by assuming that you have two separate UI applications. Should they use the same dependency resolution application(composition root)?Gaberones
@Dzenan Well as soon as it seems to be 2 different applications, I'd rather create 2 different composition root.Mindy
C
4

Please note that I think the Onion architecture (or at least the sample implementation you pointed at, as @MystereMan correctly pointed out in the comments) has a problematic spot that you should be aware about.

Although the architecture seems to favors small/focused interfaces (often with one member), the naming of these services seems to indicate otherwise. In the reference architecture for instance, there is an IShippingService class. It has one member and it therefore adheres to the Interface Segregation Principle (which is good). The name 'shipping service' however, indicates that it should contain all methods that are related to shipping. That will easily be dozens. Adding members to this interface however breaks the Interface Segregation Principle, Single Responsibility Principle (SRP) and Open Close Principle (OCP). The implementation will get big and ugly with lots of methods with little or no relationship (SRP). Implementing a new shipping requirement means adding a member and this breaks the OCP. The interface has many members while consumers often only need to call one of those members (low cohesion) and it will make unit testing harder.

Breaking it up in interfaces with all one member does solve part of the problem (and the architecture might have this intent), but this leaves you with a large amount of interfaces that have no relationship with each other, making it hard to apply cross-cutting concerns (logging, monitoring, audit trailing, validation, transactions, fault tolerance, etc) to them.

Whether or not this is a problem or not depends on a lot of factors, but the violation of one of the SOLID principles is always something to watch out for.

So as an addition to the Onion architecture, I advise you to read this article. It describes a solution to this possible shortcoming and it can be applied to the Onion architecture.

Cobb answered 15/2, 2013 at 9:45 Comment(2)
I don't think the problem you are describing is related to the architecture itself, but rather the sample implementation. I see nothing inherent in the onion architecture that requires the problems you describe.Perr
@MystereMan: Good point. I indeed only looked at the sample implementation.Cobb

© 2022 - 2024 — McMap. All rights reserved.