1
votes

I'm still gaining experience in dependency injection. I created a new console app project and added two other projects to mimic a real world app. So the three projects in my app are:

  1. MyConsoleApp
  2. MyBusinessService
  3. MyDataRepository

I created all my interfaces so that MyBusinessService is only using interfaces to get data from the repository.

My question is about MyConsoleApp. As I understand it, this is where Ninject will resolve all the dependencies.

Two questions:

  1. I think this means MyConsoleApp will have to reference both MyBusinessService and MyDataRepository. Is this correct?
  2. I think, in MyConsoleApp, I'll have to "manually" bind the IMyDataRepository interface to MyDataRepository concrete class -- see code below. Is this correct? I get a bit confused here because in some tutorials, they're mentioning that Ninject will resolve dependencies "automatically".

I think my code will look like this:

static void Main()
{
   // Get Ninject going
   var kernel = new StandardKernel();

   // Bindings
   kernel.bind<IMyDataRepository>().To<MyDataRepository>();

   // Some business logic code my console app will process
}
1

1 Answers

0
votes

Disclaimer: I am by no means a NInject expert (projects I've been on have tended to use StructureMap).

To answer question 1:
It depends. If your app code has direct dependencies on the data repository, then yes. However, it's considered by many as better practice to have the business layer wrap the data-access layer, and have the main application code depend only on the business layer (this way your application is persistence-ignorant). Your data-access layer would perform only I/O, any validation would be done in the business layer wrapper.

To answer question 2: Any code that I've seen using any DI/IoC container has calls to Bind() or an equivalent method. IoC containers do resolve dependencies "automatically" in the sense that if you inject an IFoo into a class, the container will automatically construct an appropriate instance of a class that implements IFoo. But in order for the container to do that, you have to instruct the container which class to use.

Consider the scenario where you've got a web app and occasionally connected mobile app that perform (mostly) the same function, which is managing widgets. The web app gets its data from web services. The mobile app uses a SQLite database.
You'd likely have an IWidgetRepository interface to represent data-access operations. But you'd have two implementations, one to interact with the web service, the other to interact with the SQLite DB. And both these implementations would (most likely) reside in your solution or a shared package.
In the web app, you'd bind IWidgetRepository to the web-service implementation; in the mobile app you'd bind it to the SQLite implementation. Since there are multiple implementations of the interface in question -- or, more generally, because we can't assume there will only ever be one implementation -- the container needs to be instructed as to which class/implementation to use.

Incidentally, most applications place this registration code into a separate module, frequently referred to as a "bootstrapper" (NInject actually has a class by that name), and call the bootstrapper from your startup code.