Accessing the Ninject Kernel

3,360 views
Skip to first unread message

Fred Chateau

unread,
Mar 11, 2013, 7:47:50 AM3/11/13
to nin...@googlegroups.com
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


Michael

unread,
Mar 11, 2013, 8:16:16 AM3/11/13
to ninject


On Mar 11, 6:47 am, Fred Chateau <fchat...@comcast.net> wrote:
> 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've just finished reading a book called Dependency Injection in .NET.
You can purchase it in electronic form if you are allergic to paper
copies. Good read for foundational or even gap-filling exposure.

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

Possible, but not recommended. What you end up with is a glorified
service locator. Which if you talk to some DI folks, like myself, this
is the DI anti-pattern; not far removed from if you simply called (new
ClassName()).

> 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;
>             }
>         }
>     }

I am not as familiar with the MVC pattern or with Ninject-MVC helper
facilities such as this. I've used DI more frequently in desktop
Winforms and WPF type applications.

> 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.

For obvious reasons, that's correct. Hence, aptly named "kernel". Some
containers have special rules about modules as well, something about
the object life cycles. Or just generally, clarify the term, "kernel",
"module", generally "container". Read the documentation.

> 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?

When I approach the issue, I try and keep kernel access to a minimum.
If I must, I expose instance factory to just that, a single ambient
(static) factory Get<T>(params IParameter[] args). That usually works
pretty well and keeps the DI container concern as transparent as
possible to the rest of the app.

> Regards,
>
> Fred Chateau

Michael

unread,
Mar 12, 2013, 12:06:03 AM3/12/13
to ninject
[quote]
Thank you, Michael, for your response.

Could you elaborate somewhat on exposing an instance factory or refer
me to some documentation on the subject?
[/quote]

Please keep it in the forums for everyone's benefit.

There not much to tell here. When I do, I like to wire up this concern
through a static concern, usually nearby an internal resource to my
kernel and/or module(s) operating as the DI container.

I've given the basic signature of it's Get method below. The rest I
leave as an exercise for the reader.

Fred Chateau

unread,
Mar 12, 2013, 5:12:20 PM3/12/13
to nin...@googlegroups.com
Sorry, I thought I _was_ posting it to the forums. A little confused by Google's new layout...

After spending a day reading about DI in .NET and reading just about all of Mark Seemann's entire blog, I at least learned to describe the situation with more accurate terminology. I think my problem is one of having two compositional roots in my application. And, that's because there are two places that requests can enter the application and begin the object graph

In addition to having a compositional root originating in the MVC controllers, the application also uses the MVC4 Web API, which is sort of a separate entrance path to the application. Now, there is plenty of documentation on setting up a custom dependency resolver to handle Web API, but the question that comes to mind is: Can you have more than one dependency resolver in Ninject and how would you go about wiring the two of them together?


Regards,


Fred Chateau

Michael

unread,
Mar 12, 2013, 5:19:47 PM3/12/13
to ninject


On Mar 12, 4:12 pm, Fred Chateau <fchat...@comcast.net> wrote:
> Sorry, I thought I _was_ posting it to the forums. A little confused by
> Google's new layout...

No worries here.

> After spending a day reading about DI in .NET and reading just about all of
> Mark Seemann's entire blog, I at least learned to describe the situation
> with more accurate terminology. I think my problem is one of having two
> compositional roots in my application. And, that's because there are two
> places that requests can enter the application and begin the object graph

We have some of that going on in our app. What I am finding is that,
yes, you can have different kernels going on. I'm not positive how
separate the modules are registering with the kernel. I take it with
Ninject, the kernel handles all the life cycles, while modules are a
handy way of capturing otherwise separate compositional concerns.

> In addition to having a compositional root originating in the MVC
> controllers, the application also uses the MVC4 Web API, which is sort of a
> separate entrance path to the application. Now, there is plenty of
> documentation on setting up a custom dependency resolver to handle Web API,
> but the question that comes to mind is: Can you have more than one
> dependency resolver in Ninject and how would you go about wiring the two of
> them together?

I'm not sure it works quite that way. I have an instance where I think
I have two kernels, one for UI front end concerns, and another that
appears for core engine concerns. Ninject definitely complains when
your engine interface isn't bound properly because you did so through
your UI kernel.

HTH

Fred Chateau

unread,
Mar 18, 2013, 3:50:21 AM3/18/13
to nin...@googlegroups.com

I agree...

I've spent the past several days fooling around with the Microsoft Common Service Locator and Ninject Common Service Adapter, which seemed to be more trouble than it was worth.

So, I have decided to stop worrying about running two kernels in the application. If Remo suggests a better way to handle this, I'm all open to it, but it seems reasonable to me to have a kernel per entry point into the application, so long as each kernel is dedicated to that specific method of entry.

Fred

Jarrett Meyer

unread,
Mar 18, 2013, 5:29:15 AM3/18/13
to nin...@googlegroups.com
I've done this a few different ways, and I have a sandbox project that I've added to Github. The repo says MVC3, but I've been doing it the same in MVC4. In fact, the MVC4 project is mostly linked files to the MVC3 project.

https://github.com/jarrettmeyer/sandbox/tree/master/Sandbox.MVC3

Under the Infrastructure folder, you'll find a file called DependencyConfiguration.cs. That's where my Ninject kernel is configured. Under App_Start, the NinjectWebCommon.cs calls into DependencyConfiguration.cs.

First, each of the configuration files in the Infrastructure folders could be static classes. In hindsight, I don't see why I made any of them instances.

Second, if you wanted to add a public accessor to expose the Kernel in DependencyConfiguration, would this be sufficient for your WebAPI+MVC needs?

Jarrett

--
You received this message because you are subscribed to the Google Groups "ninject" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ninject+u...@googlegroups.com.
To post to this group, send email to nin...@googlegroups.com.
Visit this group at http://groups.google.com/group/ninject?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Fred Chateau

unread,
Mar 19, 2013, 12:53:05 PM3/19/13
to nin...@googlegroups.com

Thank you, Jarrett, for your post, but at this point, 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

        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

Reply all
Reply to author
Forward
0 new messages