4
votes

I am just starting to learn Dependency Injection and I am stuck here.

My project has a WCF DataService over an Entity Framework DbContext.

public class MyDataService : DataService<MyDbContext>
{

    protected override MyDbContext CreateDataSource()
    {
        // I want to use dependency injection for this
        return new MyDbContext();
    }
}

The class is either
a) IIS hosted, so I don't have any control b) for integration tests, created with var host = new DataServiceHost(type, new Uri[] { });

both use different contstructors for MyDbContext

So basically to inject the Context with this

    protected override MyDbContext CreateDataSource()
    {
        INinjectModule module = ???; // - 
        IKernel kernel = new StandardKernel(module);
        return kernel.Get<MyDbContext>();
    }

So the question is, what is best practice in this situation? Should I:

a) Create a Module in a Class Library that both main projects and the service use b) Create a public static Variable inside the DataService project that holds the Ninject module. c) Create a public static Variable inside the DataService project that holds the Ninject kernel d) Something else.

I would prefer something like

    protected override MyDbContext CreateDataSource()
    {
        DefaultKernel.Get<MyDbContext>();
    }
1

1 Answers

3
votes

Firstly, you should have a Composition Root. That is, a single place where your Kernel is created (not in every single function).

Secondly, you don't need a NinjectModule here.. you're asking Ninject to create an instance of a concrete object (which in almost all circumstances.. defeats the purpose).

What you should create, is a separate NinjectModule pass it into the constructor of the Kernel.. something like this:

interface IContext {
}

class MyDbContext : DbContext, IContext {
}

class YourModule : NinjectModule {
    protected override void Bind() {
        Bind<IContext>().To<MyDbContext>();
    }
}

// In your composition root somewhere
var kernel = new StandardKernel(new NinjectModule[] { new YourModule() });

// in your createdatasource method
kernel.Get<IContext>();

This will get you started. Normally, your composition root is what drives injection of objects throughout your application, thereby eliminating the need to pass the Kernel around (which you will have to do in your current setup).

The hard thing to understand when starting out with DI/IoC is that it is the container's job to create your entire dependency graph. Therefore, if you setup the following bindings:

IContract1 -> ConcreteObject1
IContract2 -> ConcreteObject2
IContract3 -> ConcreteObject3

..and have the following setup:

class ConcreteObject1 : IContract1 {
    public ConcreteObject1(IContract2 contract3) {
    }
}

class ConcreteObject2 : IContract2 {
    public ConcreteObject2(IContract3 contract3) {
    }
}

If you ask your container for a concrete implementation of IContract1 (which will be ConcreteObject1), then it will create it.... BUT: ConcreteObject1 requires a concrete implementation of IContract2 in the constructor. So the container says "Wait, I know how to create this".. and passes in an instance of ConcreteObject2. Again, it says "wait, ConcreteObject2 wants a concrete implementation of IContract3.. again, it goes and fetches one.

Hopefully that helps.