1

EDIT: I forgot to move the kernel into a non-generic parent class here and supply a virtual method to access it. I do realize that the example below, as is, would create a plethora of kernel instances.

I just learned how to do injection this past week and here's how I've got things set up currently:

using Ninject;
using System.Reflection;

namespace Infrastructure
{
    public static class Inject<T>
    {
        static bool b = Bootstrap();
        static IKernel kernel;

        static bool Bootstrap()
        {
            kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());
            return true;
        }

        public static T New() { return kernel.Get<T>(); }
    }
}

And then I plan to make the various ninject module classes part of the Infrastructure namespace so that this will load them.

I haven't been able to find anything on here or Google that gives examples of how to actually organize the usage of Ninject in your project, but this seems right to me as it allows me to only need the Ninject reference in this assembly. Is this a more or less 'correct' way or is there a better design?

Brandon Moore
  • 8,590
  • 15
  • 65
  • 120

1 Answers1

4

There are a few problems with how you are doing things now.

Let me first start with the obvious C# problem: Static class variables in generic classes are shared on a per T basis. In other words, Inject<IUserRepository> and Inject<IOrderRepository> will each get their own IKernel instance, which is unlikely what you really want, since it is most likely you need a single IKernel for the life time of your application. When you don't have a single IKernel for the application, there is no way to register types as singleton, since singleton is always scoped at the container level, not at the application level. So, you better rewrite the class as non-generic and move the generic type argument to the method:

Inject.New<T>()

The second problem is one concerned dependency injection. It seems to me you are trying to use the Service Locator anti-pattern, since you are probably explicitly calling Inject.New<T> from within your application. A DI container should only be referenced in the start-up path of the application and should be able to construct a complete object graph of related objects. This way you can ask the container to get a root level object for you (for instance a Controller in the context of MVC) and the rest of the application will be oblivious to the use of any DI technology. When you doing this, there is no need to abstract the use of the container away (as you did with your Inject class).

Not all application or UI technologies allow this BTW. I tend to hide my container (just as you are doing) when working with a Web Forms application, because it is impossible to do proper dependency injection on Page classes, IHttpHandler objects, and UserControl classes.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • Actually I knew that about the generic static members being per T and I have a way to deal with that by moving the static member into a non-generic parent class and supplying a virtual method to access it. I just forgot to do it here. As for the other issue, would you mind taking a look at this question I just asked which addresses that more specificly: http://stackoverflow.com/questions/9373004/how-to-turn-this-service-locator-pattern-into-true-dependency-injection-pattern – Brandon Moore Feb 21 '12 at 06:27
  • So... does that mean that all dependencies should always be injected into the constructor (properties, or whatever) when the object is created? It seems like there would be a need to create them on the fly in the object after it's instantiated at times and this pattern would prohibit that. Is that a limitation or is my last statement an incorrect assessment? – Brandon Moore Feb 21 '12 at 06:37
  • 1
    @Steven: Fantastic answer, deleting mine. :) – Arafangion Feb 21 '12 at 06:42
  • 1
    You should indeed do constructor injection all the way. For times you need to create an instance 'on the fly', yo should create a factory and inject that. – Steven Feb 21 '12 at 12:04