11

I have read dozens of posts regarding this topic, without finding a clear guideline of how to access the Ninject.Kernel without using the Service Locator pattern.

I currently have the following in the classes that need to use CustomerBusiness (which is my service) and it works fine, but I am well aware that it is not the recommended way of doing it.

private CustomerBusiness _customerBusiness;

private ICustomerRepository CustomerRepository
{
    get { return NinjectWebCommon.Kernel.Get<IAccountRepository>(); }
}

private CustomerBusiness CustomerBusiness
{
    get
    {
        if (_customerBusiness == null)
        {
            _customerBusiness = new CustomerBusiness(AccountRepository);
        }

        return _customerBusiness;
    }
}

public Customer GetCustomer(int id)
{
    return CustomerBusiness.GetCustomer(id);
}

This is the Kernel property accessed in the code above:

public static IKernel Kernel
{
    get
    {
        return CreateKernel();
    }
}

I've read many suggestions about using a factory for this, but none of them explain how to use this factory. I would really appreciate if anyone could show me the "CustomerFactory" or any other recommended approach including how to use it.

Update

I am using ASP.NET Web Forms and need to access CustomerBusiness from CodeBehind.

Solution

The final solution that I found to be working, was the answer with the most votes found at this post: How can I implement Ninject or DI on asp.net Web Forms?

It looks like this (Note inheritance from PageBase, which is part of Ninject.Web - that is the key!):

public partial class Edit : PageBase
{
    [Inject]
    public ICustomerBusiness CustomerBusiness { get; set; }
    ...

The accepted answer below indirectly lead me to find this solution.

Community
  • 1
  • 1
Niels Brinch
  • 3,033
  • 9
  • 48
  • 75

2 Answers2

12

Since you're using NinjectWebCommon, I assume you have a web application of some sort. You really should only access the Ninject kernel in one place - at the composition root. It is the place where you are building the object graph and the only place you should ever need an access to the IoC container. To actually get the dependencies you need, you typically employ constructor injection.

In case of MVC web applications, for example, you have a controller factory using the Ninject kernel and that's the only place which references it.

To expand on your particular situation, your class would accept ICustomerBusiness in its constructor, declaring that it needs an instance of ICustomerBusiness as its dependency:

class CustomerBusinessConsumer : ICustomerBusinessConsumer
{
    private readonly ICustomerBusiness customerBusiness;

    public CustomerBusinessConsumer(ICustomerBusiness customerBusiness)
    {
        this.customerBusiness = customerBusiness;
    }
    ...
}

Now, whichever class uses ICustomerBusinessConsumer as its dependency, would follow the same pattern (accepting an instance of ICustomerBusinessConsumer as its constructor parameter). You basically never construct your dependencies manually using new (specific exceptions aside).

Then, you just have to make sure your classes get their dependencies and it's this composition root where you do this. What exactly is composition root depends on the type of an application you are writing (console application, WPF application, web service, MVC web application...)


EDIT: To get myself familiar with the situation in the ASP.NET WebForms realm I had to look up the details since I've never used it. Unfortunately, WebForms require you to have a parameterless constructor at each of your Page classes, so you can't use constructor injection all the way from the top of the object graph down to the bottom.

However, after consulting Mark Seeman's chapter on composing objects in WebForms, I can rephrase how to deal with this framework's inefficiency, while still acting in line with good DI practices:

  1. Have a class responsible for resolving the dependencies, using the Ninject's kernel you have set up. This may be a very thin wrapper around the kernel. Let's call it DependencyContainer.

  2. Create your container and save it in the application context, so that it's ready when you need it

    protected void Application_Start(object sender, EventArgs e)
    {
       this.Application["container"] = new DependencyContainer();
    }
    
  3. Let's suppose your page class (let's call it HomePage) has a dependency on ICustomerBusinessConsumer. Then DependencyContainer has to allow us to retrieve an instance of ICustomerBusinessConsumer:

    public ICustomerBusinessConsumer ResolveCustomerBusinessConsumer()
    {
        return Kernel.Get<ICustomerBusinessConsumer>();
    }
    
  4. Than in the MainPage class itself, you will resolve its dependencies in the default constructor:

    public MainPage()
    {
        var container = (DependencyContainer) HttpContext.Current.Application["container"];
        this.customerBusinessConsumer = container.ResolveCustomerBusinessConsumer();
    }
    

Few notes:

  • having the dependency container available in the HttpContext must not be tempting to consider it a service locator. In fact, the best practice here (at least from the standpoint of being true to DI) is to have some kind of "implementor" classes to which you will relay the functionality of your page classes.

    For example, each action handled by MainPage will be only relayed to its implementor class. This implementor class will be a dependency of MainPage and, as all other dependencies, will be resolved using the container.

    The important part is that these implementor classes should be in assemblies not referencing the ASP.NET assemblies and thus without a chance to access the HttpContext

  • having to write so much code to achieve this is certainly not ideal, but it is only a consequence of the framework's limitation. In ASP.NET MVC applications, for example, this is dealt with in a much better way. There you have single point where you can compose the object graphs and you don't have to resolve them in each top-level class as you have to in WebForms.

  • the good thing is that while you have to write some plumbing code in the page class constructors, from there down the object graph you can employ constructor injection

twoflower
  • 6,788
  • 2
  • 33
  • 44
  • But look at the class above. I assume you would recommend that I let my constructor take ICustomerBusiness? From where do I construct it, so the constructor injection takes effect. I have to start somewhere, right? – Niels Brinch Aug 12 '12 at 10:30
  • @NielsBrinch twoflower has actually already answered this, 'You really should only access the Ninject kernel in one place - at the composition root.' – undefined Aug 12 '12 at 10:38
  • @NielsBrinch I expanded my answer, hope it helps. If you specify what application exactly you have, I can also write more about what the composition root is in your case. – twoflower Aug 12 '12 at 10:39
  • @Niels: the composition root means that you have your kernel in one class, available from there to everyone else. In practice this means that either you have a shared class and expose the kernel or hide the kernel and expose a method to resolve dependencies (create objects). – Wiktor Zychla Aug 12 '12 at 10:41
  • Great, we're getting somewhere! Let's focus on the class that **uses** CustomerBusinessConsumer. This will have to somehow access Kernel, maybe through a factory, if I understand the composition root recommendation for webapps correctly. Won't this result in more or less the same code as I posted originally? – Niels Brinch Aug 12 '12 at 10:43
  • @NielsBrinch No, it won't, that's the point. It again will have an instance of `ICustomerBusinessConsumer` as its constructor parameter. Now let's suppose that this class (using `ICustomerBusinessConsuer`) is at the very top of the object graph (in MVC case, it's a controller). You just have to be sure, that whatever constructs these top-level classes has access to your Ninject factory so that it is able to compose the whole `object graph` at once. What application type exactly do you have (MVC, web service...)? – twoflower Aug 12 '12 at 10:49
  • ASP.NET Web Forms - so I need to access CustomerBusiness from my CodeBehind. Sorry for not clarifying this originally. – Niels Brinch Aug 12 '12 at 10:57
  • Thanks a bunch for the update. In effect, it seems very much like instead of exposing Kernel, there is a wrapper which indirectly exposes Kernel through it's specific methods. Is it that these specific methods are declared that makes it a better choice than simply exposing Kernel? – Niels Brinch Aug 12 '12 at 13:57
  • Yes, I believe you could get by with directly accessing the Kernel and asking it to resolve the dependencies. One case where you would have to use a wrapper would be when Ninject would not provide a way to configure some more intricate dependencies (e.g. dependencies depending themselves on some external configuration file) but from my own experience (I am using Ninject myself) that rarely happens as Ninject is strong enough. The important is not whether Ninject directly/indirectly but **only at a single place for each page** – twoflower Aug 12 '12 at 18:07
1

Constructor injection is the preferred method for DI with ninject, however it also supports property injection. Take a read of the ninject page around injection patterns here https://github.com/ninject/ninject/wiki/Injection-Patterns.

Both of these are injection patterns unlike service location which is request based, not really injection at all.

The flipside of injection is that you need to control construction. When using MVC all of the wiring to do this is built into the MVC ninject package on nuget

undefined
  • 33,537
  • 22
  • 129
  • 198
  • I use constructor injection everywhere else, for example, the repository goes in the constructor of the business class and it works great. But I have to start somewhere, right? I can't use constructor injection in the class that just needs to use the class. – Niels Brinch Aug 12 '12 at 10:28
  • @NielsBrinch normally in your application you have a single entry point, in webapps this revolves around global.ascx, in console apps this revolves around Program.Main, normally ninject is configured at this level and anything below this is constructed with ninject. If you are in a webapp there are packages which will set this up for you so that onrequest things are instantiated from the kernel. The same is true to a lesser degree for WPF and silverlight. If you are in another app type its likely you will have to construct your ancestor object manually from the kernel – undefined Aug 12 '12 at 10:35
  • I am in a webapp. I construct the Kernel in an equivalent of global.asax (App_Start/NinjectWebCommon). Do you suggest I create CustomerBusiness etc. in this class too and put them somewhere to use later? – Niels Brinch Aug 12 '12 at 10:39
  • @NielsBrinch if you are in a webapp, you actually only want your object once youve gotten a request. At this point ninject will instantiate or reuse your CustomerBusiness for use within that request – undefined Aug 12 '12 at 10:41
  • What does this look like? Think code-behind that does not have a constructor and needs to use a CustomerBusiness. – Niels Brinch Aug 12 '12 at 10:48
  • So for a page codebehind, it should have a constructor, then ninject plugs into the httpapplication and controls the construction of the page – undefined Aug 12 '12 at 11:46
  • How does this look specifically? – Niels Brinch Aug 12 '12 at 12:24
  • After getting some of the right terms and keywords from this question, I researched and found Ninject.Web extension which I am now attempting to implement. I guess this is the right answer in this question too ... http://stackoverflow.com/questions/4933695/how-can-i-implement-ninject-or-di-on-asp-net-web-forms – Niels Brinch Aug 12 '12 at 13:54