This project is read-only.

Integration in Onion Architecture

Feb 15, 2013 at 7:30 AM
Edited Feb 15, 2013 at 8:01 AM
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 Simple Injector in 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 (to tie them together).
Coordinator
Feb 15, 2013 at 9:20 AM
To get things running, you'll need to include the Simple Injector ASP.NET Integration NuGet package to the DependencyResolution project and replace the NinjectWebCommon and NinjectServiceLocator classes with the following:
using Core;
using Core.Domain;
using Core.Services;
using Core.Services.Impl;
using DependencyResolution.App_Start;
using Infrastructure.EntityFramework;
using Infrastructure.Services;
using SimpleInjector;
using UI.Services;

[assembly: WebActivator.PreApplicationStartMethod(typeof(SimpleInjectorWebCommon), "Start")]

namespace DependencyResolution.App_Start
{
    public static class SimpleInjectorWebCommon
    {
        public static void Start()
        {
            var container = new Container();

            RegisterServices(container);
        }

        private static void RegisterServices(Container container)
        {
            container.RegisterPerWebRequest<IDataContext, EfDataContext>();
            container.Register<IUserSession, HttpUserSession>();
            container.Register<IShippingService, AcmeShippingServiceAdapter>();
            container.Register<IInventoryService, ContosoInventoryServiceAdapter>();
            container.Register<ILogger, Log4NetLogger>();
            container.Register<IOrderProcessor, PayPalOrderProcessor>();
            container.Register<IShoppingCartProcessor, ShoppingCartProcessor>();

            ServiceLocator.SetServiceLocator(() => new SimpleInjectorServiceLocator(container));
        }
    }
}
and
using System;
using System.Collections.Generic;
using Core;
using SimpleInjector;

namespace DependencyResolution
{
    public class SimpleInjectorServiceLocator : IServiceLocator
    {
        private readonly Container _container;

        public SimpleInjectorServiceLocator(Container container)
        {
            _container = container;
        }

        public T GetInstance<T>()
        {
            return (T)GetInstance(typeof(T));
        }

        public object GetInstance(Type type)
        {
            return ((IServiceProvider)_container).GetService(type);
        }

        public IEnumerable<object> GetAll(Type serviceType)
        {
            return _container.GetAllInstances(serviceType);
        }

        public IEnumerable<T> GetAll<T>()
        {
            return _container.GetAllInstances<T>();
        }
    }
}
I haven't tested it, but it shouldn't take much more to get started.

Good luck.
Marked as answer by dot_NET_Junkie on 11/5/2013 at 7:35 AM
Feb 15, 2013 at 9:54 AM
That works like a charm! Thanks!
Mar 17, 2014 at 4:42 AM
Hi, I'm a newbie with Onion and Simple Injector, and this post has helped me a lot, but one question, what about IServiceLocator ?? where does it located, I can't locate it ?

Thanks.
Coordinator
Mar 17, 2014 at 7:46 AM
That IServiceLocator interface is an abstraction that is defined in the project that Vocte referenced.
Mar 18, 2014 at 6:23 AM
Thank you, it works, another question, on building the project, I'm getting..
'Quotation.Infrastructure.DependencyResolution.SimpleInjectorServiceLocator' does not implement interface member 'System.IServiceProvider.GetService(System.Type)', any clue ?

Thanks in advance.
--JR
Coordinator
Mar 18, 2014 at 7:01 AM
Edited Mar 18, 2014 at 7:56 AM
uhhh.. you could implement that method?
Coordinator
Mar 18, 2014 at 11:39 AM
System.IServiceProvider is a Microsoft defined abstraction and is not something from the Onion Architecture or Simple Injector.

However, the Simple Injector Container does implement this interface so to offer some basic advice without having visibility of your code I suggest you need to have a reference to the container in whatever class is throwing the error.
Mar 23, 2014 at 3:33 AM
Hi guys!, I really appreciate your feedback, and sorry for my delay but I've been a little busy attending a critical Java project, and well, taking up this matter, according to my understanding Simple Injector must to provide me the IServiceLocator abstraction and the Container too, doesn't it ? So far I have the following project references in my project: SimpleInjector; SimpleInjector.Diagnostics; SimpleInjector.Integration.Web and SimpleInjector.Integration.Web.Mvc; but it looks like none of the works, I guess SimpleInjector package should do it.

qujk, what do you mean about "..to have a reference to the container in whatever class" is throwing the error ? Do you mean to extend SimpleInjectorServiceLocator from Container ?

I appreciate your feedback in advance.
Cheers!
Coordinator
Mar 23, 2014 at 10:03 AM
@jerori I'm a little confused here - you mention System.IServiceProvider.GetService(System.Type) in one post and IServiceLocator in the next. We have no visibility of your code so it is almost impossible to figure out what may be wrong. Show the whole exception and the code where it is happening and maybe we can figure it out.
Mar 23, 2014 at 7:01 PM
Edited Mar 23, 2014 at 10:05 PM
Hi guys, well my case is exactly the same like Vocte, I'm trying to replace Ninject by SImpleInjector; I followed the last dot_NETjunkie feedback with success. Let me talk to you a bit about the project (learning curve)

My Project Onion Architecture:
Domain
Infrastructure .. [A Solution Folder]
|-- ..DependencyResolution .. [A project]
°-- ContextDependExtensions.cs .. [A class]
°-- DependencyContext.cs
°-- ServiceLocator.cs
°-- SimpleInjectorServiceLocator.cs
°-- SimpleInjectorWebCommon.cs

|-- ..Interfaces
°-- ILoggingService.cs
°-- .. Logging
°-- LoggingService.cs
°-- UtcDateRender.cs
°-- WebVariablesRender.cs

|-- ..Services
°-- ..Application

|-- User
°-- ..Web.UI


So what I'm doing is jut to replace Ninject IoC by SimpleInjector as follow.
°-- SimpleInjectorWebCommon.cs
    public static class SimpleInjectorWebCommon
    {
        private static ILoggingService GetLoggingService()
        {
            ConfigurationItemFactory.Default.LayoutRenderers
                .RegisterDefinition("utc_date", typeof(UtcDateRenderer));
            ConfigurationItemFactory.Default.LayoutRenderers
                .RegisterDefinition("web_variables", typeof(WebVariablesRenderer));
            ILoggingService logger = (ILoggingService)LogManager.GetLogger("NLogLogger", typeof(LoggingService));
            return logger;
        }


        public static void Start()
        {
            var container = new Container();

            RegisterServices(container);
        }

        private static void RegisterServices(Container container)
        {
            ILoggingService logger = GetLoggingService();

            container.RegisterWithContext<ILoggingService>(dependencyContext => {
                return logger;
            });

            ServiceLocator.SetServiceLocator(() => new SimpleInjectorServiceLocator(container));  // HERE the problem during building.. I used IServiceProvider before instead .SetServiceLocator(), but is oki now with .SetServiceLocator().

        }
    }
°-- SimpleInjectorServiceLocator.cs
   public class SimpleInjectorServiceLocator : IServiceLocator
    {
        private readonly Container _container;

        public SimpleInjectorServiceLocator(Container container)
        {
            _container = container;
        }

        public T GetInstance<T>()
        {
            return (T)GetInstance(typeof(T));
        }

        public object GetInstance(Type type)
        {
            return ((IServiceProvider)_container).GetService(type);
        }

        public IEnumerable<object> GetAll(Type serviceType)
        {
            return _container.GetAllInstances(serviceType);
        }

        public IEnumerable<T> GetAll<T>()
        {
            return _container.GetAllInstances<T>();
        }
    }
Now, my controller is calling to the logger without success, I added the reference to |-- Infrastructure.Interfaces project
    public class HomeController : Controller
    {
        private readonly ILoggingService _logger;

        public HomeController(ILoggingService logger)
        {
            _logger = logger;
        }
[InvalidOperationException: An error occurred when trying to create a controller of type 'eQuotation.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]

Thanks for your feedback in advance.
--JR
Coordinator
Mar 23, 2014 at 10:10 PM
What you're probably missing is a reference to the CommonServiceLocator.SimpleInjectorAdapter project. When you downloaded this project from NuGet, you can do the following:
var serviceLocator = 
    new CommonServiceLocator.SimpleInjectorAdapter.SimpleInjectorServiceLocatorAdapter(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
Mar 23, 2014 at 11:23 PM
Thanks do_Net_Junkie, what I did is:
            container.RegisterWithContext<IServiceProvider>(dependencyContext =>
            {
                return serviceLocator;
            });
instead of
           ServiceLocator.SetServiceLocator(() => serviceLocator);   // SetServiceLocator  instead of SetLocatorProvider   :)
but without success:
[InvalidOperationException: An error occurred when trying to create a controller of type 'eQuotation.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]

--JR
Coordinator
Mar 24, 2014 at 8:52 AM
Since you are doing MVC, you will haver to use the MVC integration. Using this integration package you can set a Simple Injector specific MVC Dependency Resolver as follows:
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
btw, what's the idea of registering the IServiceProvider as contextual dependency? You even don't use the dependencyContext parameter at all. You can simply do:
container.RegisterSingle<IServiceProvider>(serviceLocator);
But to be honest, try to prevent injecting that IServiceProvider into your application classes. Letting your application logic use the container or an abstraction of it lead to the Service Locator anti-pattern.
Mar 25, 2014 at 2:51 PM
Thanks do_Net_Junkie!, this worked perfect through DependencyResolver.SetResolver !, definetely I was following the wrong guideline, finally I saw something about my logger (I'm starting the project you know) in the console, but not in the file.txt (log file is not being created) and I have googled it without success, I know this could be out of the scope of your help, but do you have any idea about why ?

What I already did is:
On NLog.config file: Copy the output Directory = Copy ALways; Build Action = Content and On Tools -> Options -> Debugging > Step over prperties and operators checkbox is clean.

Also I have added to the .config file:
      throwExceptions="true"
      internalLogLevel="Trace"
      internalLogFile="D:\\nlogproblems.txt"
Any clue ?, I appreciate your feedback.
-- JR
Coordinator
Mar 25, 2014 at 2:57 PM
I'm sorry, that question is out of my league. You might want to try at Stackoverflow.com.