Accessing the Ninject Kernel Globally
Asked Answered
O

4

21

This question is not specifically related to Ninject. It's more of a general coding question, but I'm posting it here in case there might be a better way entirely of handling the issue in Ninject, than what I am trying to do.

I would like to know whether it is possible to access the Ninject Standard Kernel globally, from its instance in Global.asax.

Here is the code:

public class MvcApplication : NinjectHttpApplication
{
    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();

        // MVC global registration, routing and filtering code goes here...
    }

    protected override IKernel CreateKernel()
    {
        return Container;
    }

    private static IKernel Container
    {
        get
        {
            IKernel kernel = new StandardKernel();
            kernel.Load(new ServiceModule(), new RepositoryModule());
            return kernel;
        }
    }
}

If I have some classes, for example, facade classes that do not interface with the controllers, where I would like to begin a dependency chain, my understanding is I should use:

_className = kernel.Get<IClassName>();

However, the only way I know of to do this is to create a new instance of the Ninject Standard kernel, but if I understand correctly, is is not a good idea to create a new instance of the Ninject kernel, because that is basically creating a second kernel.

So, is it possible to access the existing Kernel that was instantiated in Global.asax at Application Start, from anywhere in my application, or is there a better way entirely to do this?

Regards,

Fred Chateau

Ordure answered 11/3, 2013 at 12:5 Comment(0)
W
28

The most simple way (IMO):

_className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));
Whitby answered 25/10, 2013 at 8:58 Comment(1)
Thanks Vasilij, this saved my life!!!! I used it to set up data injection in a non MVC class.Zlatoust
C
9

Newer version of Ninject has this method if used with System.Web.MVC:

var obj = DependencyResolver.Current.GetService<IClassName>();

Unless you need to manipulate DI bindings on the fly, but instantiating a StandardKernel is a little heavy.

IKernel kernel = new StandardKernel();
var obj = DependencyResolver.Current.GetService<IClassName>();
Colyer answered 12/10, 2017 at 15:23 Comment(2)
is there any preconditions for this to work? I tried and it only returns nullChavers
This, DependencyResolver.Current.GetService<IClassName>() worked for me well for Ninject v 3.20 & Ninject.Web/MVC5 3.2.1Bach
O
2

I managed to get the Service Locator working, and it appears to be working quite well. When a request enters the application through an MVC Controller Action Method, Ninject functions in the normal way provided by Ninject.Mvc.Extensions. It injects instance classes through the controller constructor. When a request enters the application in any other way, I call the Service Locator to supply the instance classes in that classes constructor.

Here's the code:

First, a reference to Microsoft.Practices.ServiceLocation

And the following Ninject adapter class.

public class NinjectServiceLocator : ServiceLocatorImplBase
{
    public IKernel Kernel { get; private set; }

    public NinjectServiceLocator(IKernel kernel)
    {
        Kernel = kernel;
    }

    protected override object DoGetInstance(Type serviceType, string key)
    {
        return Kernel.Get(serviceType, key);
    }

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
    {
        return Kernel.GetAll(serviceType);
    }
}

And in Global.asax

public class MvcApplication : NinjectHttpApplication
{
    private static IKernel _kernel;


    protected override IKernel CreateKernel()
    {
        return Container;
    }

    private static IKernel Container
    {
        get
        {
            if (_kernel == null)
            {
                _kernel = new StandardKernel();
                _kernel.Load(new ServiceModule(), new RepositoryModule());

                ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel));
            }

            return _kernel;
        }
    }
}

Note this code requires the use of Ninject.Mvc.Extensions, which provides dependency resolver fallback to the default controller. Otherwise, a custom dependency resolver may be required.

This appears to resolve all my concerns. It creates the instance classes, resolves the entire object graph, and works from anywhere I need it to work. And, as far as I can tell, there is only one Ninject Standard Kernel per application.

I know using the Service Locator pattern is frowned upon, but I imagine using more than one Ninject kernel would be frowned upon even worse.

Fred Chateau

Ordure answered 19/3, 2013 at 20:5 Comment(0)
C
0

It sounds like you're needing more of a Factory pattern implementation of Ninject. You could migrate the Kernel from the Global.asax to a Factory class which could be interacted with by the rest of your application.

Alternatively if you have a situation where a parameter specified at runtime is to determine the interface bindings you could wrap the service. This is a hybrid setup of DI and ServiceLocater, but the ServiceLocater only occurs at service level instantiation, all other layers are coded normally in a DI/IOC pattern.

MyService : IService1
{
    public void DoSomething(MyCustomParameter parameter)
    {
        //Builds the Kernel using the supplied parameter
        //We've in our resolver bound IService1 To MyActualService
        var trueService = kernel.Get<IService1>();
        return trueService.DoSomething(parameter);
    }
}

MyActualService : IService1
{
    public void DoSomething()
    {
        //Do the Actual work
    }
}
Catalpa answered 11/3, 2013 at 13:20 Comment(2)
Would you happen to know how setting up for a factory would affect the MVC Extensions implementation?Ordure
Sadly that part I would not know without attempting it. I've used the wrapping method listed above for the application I'm working on due to unique concerns and architecture choices.Catalpa

© 2022 - 2024 — McMap. All rights reserved.