Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject bind different implementations

Tags:

c#

.net

ninject

I've been using Ninject for a short time, and I'm trying to figure out how to do something that I've done in Unity with app.config/web.config entries.

I'm pretty sure this is simple, just haven't found the best way to implement it, and of course Ninject doesn't have the greatest documentation around.

I want to have different implementations for an interface, with no change in the code - the specific application knows which implementation to use.

For example, when I used Unity, I would have a live app and a unit test library, using different data libraries. So:

var repo = IoC.Get<IRepository>();

would return a RealRepository in my live app, and a FakeRepository in my unit tests. I would simply map the classes in my app.config or web.config.

In Ninject, since you define the mappings in the code, there doesn't seem to be a way to decide which implementations (or which module) you use, except in the code - but of course the whole purpose is I don't want to have to specifically state which implementation I want to use.

Is there a good way to do this? The only way I can think is to dynamically choose the NinjectModule implementation from the config file, but that just doesn't feel right.

like image 569
Joe Enos Avatar asked Dec 27 '22 23:12

Joe Enos


2 Answers

Is sounds like you are missusing an IoC container as Service Locator. This gives you many problems. One of it is that testing is much more difficult. I suggest to do it right instead and do constructor injsction instead of service location.

This means instead of

public class MyClass
{
    public void Do()
    {
        var repo = IoC.Get<IRepository>();
        ....
    }
}

You do

public class MyClass
{
    private IRepository repo;
    public MyClass(IRepository repo)
    {
        this.repo = repo;
    }

    public void Do()
    {
        ....
    }
}

There is just one Get for the root of your application. Everything else is passed through constructors.

It makes testing really simple:

var testee = new MyClass(new Mock<IRepository>());
like image 93
Remo Gloor Avatar answered Jan 12 '23 23:01

Remo Gloor


Doesn't your live app and your unit test libraries have different endpoints? One is presumably a unit test project (nunit?) and the other is an application, (console, windows, or asp.net).

Each type of app should define their bindings independently, usually by defining separate modules (that you pass to the constructor of StandardKernel). One set provides mappings for your real app, and another provides mappings for your unit tests. The latter may or may not be necessary -- ideally the dependencies of a particular class you are testing should be easily mocked and passed in without using Ninject at all. In practice, I've found many excuses where it was convenient to still use Ninject, in which case I create either a separate module or just rebind the kernel on the fly in the test itself.

like image 35
Kirk Woll Avatar answered Jan 13 '23 00:01

Kirk Woll