I'm a newbie when it comes to DI and ninject and I'm struggling a bit about when the actual injection should happen and how to start the binding.
I'm using it already in my web application and it working fine there, but now I want to use injection in a class library.
Say I have a class like this:
public class TestClass
{
[Inject]
public IRoleRepository RoleRepository { get; set; }
[Inject]
public ISiteRepository SiteRepository { get; set; }
[Inject]
public IUserRepository UserRepository { get; set; }
private readonly string _fileName;
public TestClass(string fileName)
{
_fileName = fileName;
}
public void ImportData()
{
var user = UserRepository.GetByUserName("myname");
var role = RoleRepository.GetByRoleName("myname");
var site = SiteRepository.GetByID(15);
// Use file etc
}
}
I want to use property injection here because I need to pass in a filename in my constructor. Am I correct in saying that if I need to pass in a constructor parameter, I cannot use constructor injection? If I can use constructor injection with additional parameters, how do I pass those parameters in?
I have a console app that consumes by Test class that looks as follows:
class Program
{
static void Main(string[] args)
{
// NinjectRepositoryModule Binds my IRoleRepository etc to concrete
// types and works fine as I'm using it in my web app without any
// problems
IKernel kernel = new StandardKernel(new NinjectRepositoryModule());
var test = new TestClass("filename");
test.ImportData();
}
}
My problem is that when I call test.ImportData()
my repositories are null - nothing has been injected into them. I have tried creating another module and calling
Bind<TestClass>().ToSelf();
as I thought this might resolve all injection properties in TestClass
but I'm getting nowhere.
I'm sure this is a trivial problem, but I just can't seem to find out how to go about this.
You are directly newing TestClass
, which Ninject has no way of intercepting - remember there's no magic like code transformation intercepting your new
s etc.
You should be doing kernel.Get<TestClass>
instead.
Failing that, you can inject it after you new
it with a kernel.Inject( test);
I think there's an article in the wiki that talks about Inject
vs Get
etc.
Note that in general, direct Get
or Inject
calls are a Doing It Wrong smell of Service Location, which is an antipattern. In the case of your web app, the NinjectHttpModule
and PageBase
are the hook that intercepts object creation - there are similar interceptors / logical places to intercept in other styles of app.
Re your Bind<TestClass>().ToSelf()
, generally a StandardKernel
has ImplicitSelfBinding = true
which would make that unnecessary (unless you want to influence its Scope to be something other than .InTransientScope()
).
A final style point:- you're using property injection. There are rarely good reasons for this, so you should be using constructor injection instead.
And do go buy Dependency Injection in .NET by @Mark Seemann, who has stacks of excellent posts around here which cover lots of important but subtle considerations in and around the Dependency Injection area.