Wrapping the Ninject Kernel with ServiceLocator

I was a big fan of using Unity or Mef for IoC in my apps, we used Prism heavily in one of my past projects with Silverlight. Prism offered a IoC with your choice of Unity or Mef for your container as well as very good approach to building a scalable application with the notion of Prism Modules.

I recently came on board to a project extensively using Ninject for our MVC3 application. Ninject has the notion of a Kernel which is pretty much how you access your container of registered or bound instances.

In the event where you would ever change out or switch your IoC implementation or choice of frameworks, a nice wrapper, that wrapped your method of accessing your container would be great. You can in theory switch out your IoC (container) with Mef, Unity, Sprint.NET, AutoFac, Castle Windsor, or any other IoC framework with minimal refactoring (here’s a great list of some popular IoC frameworks from Scott Hanselman). 

With a little research I found that Ninject has a ServiceLocator adapter that you can wire up when you setup your Kernel. With this wired up you can access your Ninject container with the standard Microsoft ServiceLocator, which is also a widely used pattern.

For this demonstration we are just going to use the MVC3 application used from my previous blog: http://blog.longle.net/2012/02/15/inject-ioc-my-mvc3-application-in-less-than-5-minutes/

  1. Right click your references folder and click “Manage NuGet Packages”
  2. Search for ServiceLocator, and install the CommonServiceLocator.NinjectAdapter Package
  3. You should now see the NinjectAdapter reference added
  4. Let’s wire this up now, we will visit the Global.asax.cs file where we setup and initialized our Kernel (container), here’s where we an register the NinjectServiceLocator Adapter with Microsoft.Practices.ServiceLocation.ServiceLocator interface.
    
            protected void Application_Start()
            {
                RegisterMyDependencyResolver();            
                AreaRegistration.RegisterAllAreas();
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<IHelloWorldService>().To<HelloWorldService>();
                ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(standardKernel));
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  5. So the first place I wanted to use the ServiceLocator was in our MyDependendencyResolver class, where the MVC runitme routes all request get instances for all your registered or bound interfaces. What happens here is that when the MVC runtime requests for a registered instance of a specific interface and your container does not have one, MVC expects a your IoC container to return a null value and at this point MVC will fallback and attempt to return the default instance.

    For example if the MVC runtime requests for an IControllerFactory and you didn’t setup a binding or registration for this interface the MVC runtime will just return a DefaultControllerFactory in this case. The Ninject Kernel will automatically return null in this case.

    However when using the ServiceLocator interface, there is not a TryGet method like the Ninject Kernel offers when requesting instance, the TryGet method will actually scan the container for any registrations for a given interface and if it doesn’t find one it will return null for you.

    So I have to admit there wasn’t a way to really elegantly handle this. So to mimic this behaivor, which is returning a null when we weren’t able to find any registrations with the ServiceLocator, I had to wrap they request and catch the Microsoft.Practices.ServiceLocation.ActivationException, and if this exception was caught then we would return null so that the MVC runtime could take over and return default instances e.g. when requesting the IControllerFactory, ServiceLocator would return null, and MVC would take over and return the DefaultControllerFactory.

    Here’s the exception before wrapping the request:

    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                    return ServiceLocator.Current.GetInstance(serviceType);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                    return ServiceLocator.Current.GetAllInstances(serviceType);
            }
        }
    
    

  6. After wrapping the request to our container and returning null after scanning our container and not finding a registered instance for that interface, in our case the IControllerFactory.
    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                try
                {
                    return ServiceLocator.Current.GetInstance(serviceType);
                }
                catch (Microsoft.Practices.ServiceLocation.ActivationException ex)
                {
                    return null;
                }
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                try
                {
                    return ServiceLocator.Current.GetAllInstances(serviceType);
                }
                catch (Microsoft.Practices.ServiceLocation.ActivationException ex)
                {
                    return null;
                }
            }
        }
    
    

    Obviously we could create a two extension methods for ServiceLocator maybe TryGet and TryGetAll, but in the interest of time we’ll skip that for now.

    Note, you can always use ServiceLocator everywhere else in your application when requesting for instance(s) for a given interface from your Kernel and leave our former implementation of MyDependencyResolver accessing the Ninject Kenerl directly if you are uncomfortable with wrapping it with the try/catch block to return null, so that the MVC runtime can fallback and return default instances e.g. IControllerFactory -> DefaultControllerFactory.

    Again, not the most elegant way, however when doing a deep dive on the TryGet method from the Ninject Kernel with Reflector I notice that we weren’t to far off from what Ninject was actually doing here.

  7. If you look at the GetValue method that we reflected on (which is what eventually get’s called by the Ninject’s _kernel.TryGet method, notice the return statement ending with the lambda expression SingleOrDefault()
    
    protected virtual object GetValue(Type service, IContext parent)
    {
        Ensure.ArgumentNotNull(service, "service");
        Ensure.ArgumentNotNull(parent, "parent");
        IRequest request = parent.Request.CreateChild(service, parent, this);
        request.IsUnique = true;
        return parent.Kernel.Resolve(request).SingleOrDefault<object>();
    }
    
    

    which returns null if a registration was not found for that interface in our Ninject container.

    Obviously wrapping our request and catching the ActivationException, we are swallowing the exception, which could create some difficulties in debugging true exceptions where things weren’t wired up correctly for Ninject to bind and activate instances to return to us.

  8. Now let’s see do a quick demonstration on using the ServiceLocator pattern other than in our MyDependencyResolver class. Let’s revisit the HomeController where we were orginall injected the IHelloWorldService in the constructor. An alternative way here is we can manually get this injected by requesting it with ServiceLocator.
    Before:
    
        public class HomeController : Controller
        {
            private readonly IHelloWorldService _helloWorldService;
    
            public HomeController(IHelloWorldService helloWorldService)
            {
                _helloWorldService = helloWorldService;
            }
    
            public ActionResult Index()
            {
                ViewBag.Message = _helloWorldService.Hello(@"Welcome to ASP.NET MVC!");
                return View();
            }
    
            public ActionResult About()
            {
                return View();
            }
        }
    
    

    After:

    
        public class HomeController : Controller
        {
            private readonly IHelloWorldService _helloWorldService;
    
            public HomeController()
            {
                _helloWorldService = ServiceLocator.Current.GetInstance<IHelloWorldService>();
            }
    
            public ActionResult Index()
            {
                ViewBag.Message = _helloWorldService.Hello(@"Welcome to ASP.NET MVC!");
                return View();
            }
    
            public ActionResult About()
            {
                return View();
            }
        }
    
    

    Now it’s really preference whether you want the MVC runtime to use our MyDependencyResolver in conjunction with Ninject to automagically figure out what needs to be injected like in our [before] case which was injecting the IHellowWorldService in the constructor of HomeController, or manually requesting it using ServiceLocator.

    Again I don’t see a wrong or right in eithier way, it’s just really preference, I prefer going with our before case where we let MyDependencyResolver and Ninject figure out what, when and where things automagically need to be injected, however I just wanted to demonstrate abstracting Ninject’s Kernel with ServiceLocator if you wanted to have the flexibility of easiliy swapping out our choice of IoC frameworks with mininmal refactoring or code change. 🙂

Download sample application: https://skydrive.live.com/redir.aspx?cid=949a1c97c2a17906&resid=949A1C97C2A17906!371&parid=949A1C97C2A17906!361

Inject (IoC) my MVC3 Application in less than 5 minutes…!

Quickest way to get your MVC3 application up and running with IoC (Inverse of Control) pattern. So let’s start off by first choosing an IoC framework, for this example we will use Ninject, however your more than welcome to choose other IoC frameworks such as Unity, Mef, AutoFac, etc.. I personally prefer Mef, however in this example we will use Ninject so that we can demonstrate how to implement the ServiceLcoator interface to wrap your chose of Ninect container which is accessed by Ninject Kernel, this can come in handy later if you ever decide to switch out your choice of IoC framework.

So let’s start with a fresh new MVC3 application, the first thing on our TODO list is to add Ninject, we are in luck here since we can easily add this with NuGet.

  1. Right click references in your MVC3 project and choose Manage NuGet Packages
  2. Search for “Ninject” in the Search textbox
  3. Your application should be wired up with the Ninject reference added to your project
  4. Add a class named “MyDependencyResolver.cs” anywhere in your MVC3 project, and have it impelment the IDependencyResolver interface. This will allow you to plug pretty much anything into the MVC runtime. The System.Web.Mvc.IDependencyResolver will have two methods that you will need to implement GetService and GetServices.
    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                throw new NotImplementedException();
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                throw new NotImplementedException();
            }
        }
    
    
  5. Now let’s wire up our Ninject Kernel (container) in this class MyDependencyResolver.cs
    
        public class MyDependencyResolver : IDependencyResolver
        {
            private readonly IKernel _kernel;
    
            public MyDependencyResolver(IKernel kernel)
            {
                _kernel = kernel;
            }
    
            public object GetService(Type serviceType)
            {
                return _kernel.TryGet(serviceType, new IParameter[0]);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                return _kernel.GetAll(serviceType, new IParameter[0]);
            }
        }
    
    

    We create a constructor that accepts IKernel as a parameter, this is where and how the Ninject Kernel will be injected into this class.

  6. Now what we need to do is register MyDependencyResolver with the MVC runtime so that it knows to use it. So let’s head over to Application_Start() in our Global.asax class to wire this up. Here we add a helper method “RegisterMyDependencyResolver” which we will instantiate a new instance of StandardKernel and register it with the MVC runtime using DependencyResolver.SetResolver method which accepts a parameter of IDependencyResolver which our MyDependencyResolver class implemeneted.
    
            protected void Application_Start()
            {
                RegisterMyDependencyResolver();            
                AreaRegistration.RegisterAllAreas();
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  7. Now if we setup a breakpoint on our GetService method we will see that the MVC runtime will first request an instance of System.Web.Mvc.IControllerFactory, now since we haven’t registered or bound an actual class which implements the IControllerFactory interface, our GetService method will just return null, and the MVC runtime will just default to the default ControllerFactory. Now if we had a custom ControllerFactory and had it registered, this would have returned our own instance.

    As you break on on the GetService method, you will notice that the MVC runtime will also request an instance of IControllerActivator, HomeController, IViewPageActivator, Home_Index_cshtml.

  8. Now let’s demonstrate a simple HelloWold injection example. First we want to program against an interface, IHelloWorld with the a method Hello(string message).

    
        public interface IHelloWorldService
        {
            string Hello(string message);
        }
    
    
    

    Now let’s implement this interface, create a HelloWorldService.cs class and implement this interface.

    
        public class HelloWorldService : IHelloWorldService
        {
            public string Hello(string message)
            {
                return message;
            }
        }
    
    
  9. Now we have to register our concrete implementation HelloWorldService to our IHelloWorldService with our container (Kernel), will do this in our Global.asax where we originally fired up our Kernel.
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<IHelloWorldService>().To<HelloWorldService>();
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  10. Now if we setup a breakpoint in the constructor of our HomeController we will see that the IHomeController parameter will be hydrated by our GetService method of our MyDependencyResolver.GetService method which we registerd as our DependencyResolver with the MVC runtime, this is DependencyInjection.

Download sample: https://skydrive.live.com/redir.aspx?cid=949a1c97c2a17906&resid=949A1C97C2A17906!370&parid=949A1C97C2A17906!361

Stay tuned for Part 2, where we will wire up the ServiceLocator to wrap how we retrieve registered instances so in the event where we wanted to switch out our IoC framework (e.g. Unity, Mef, AutoFac, StructureMap) we would have very little refactoring and code change.