I have added the NLog, Ninject, Ninject.Extensions.Logging, Ninject.Extensions.Logging.NLog2, and WebApiContrib.IoC.Ninject packages into my .NET Web API v2 project. I modified the CreateKernel method inside the standard NinjectWebCommon file, because without these lines I wasn't able to get *anything* to resolve:
private static IKernel CreateKernel ()
{
var kernel = new StandardKernel ();
kernel.Bind<Func<IKernel>> ().ToMethod (ctx => () => new Bootstrapper ().Kernel);
kernel.Bind<IHttpModule> ().To<HttpApplicationInitializationHttpModule> ();
RegisterServices (kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver (kernel);
ControllerBuilder.Current.SetControllerFactory (new NinjectControllerFactory (kernel));
return kernel;
}
....where NinjectResolver comes from WebApiContrib.IoC.Ninject and NinjectControllerFactory is below:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel;
public NinjectControllerFactory ( IKernel kernel )
{
this.kernel = kernel;
}
protected override IController GetControllerInstance ( RequestContext requestContext, Type controllerType )
{
return controllerType == null ? null : (IController) kernel.Get (controllerType);
}
}
I found the NinjectControllerFactory idea somewhere in the internet and it has allowed my controller classes to very conveniently rely on constructor and property injection, which seems to work.
My first question is - from what I read, I initially thought that Ninject would auto-magically wire itself up as the global dependency resolver, so i was surprised i needed to add the line:
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver (kernel);
...at all. Am I doing something wrong, or is that standard practice, to explicitly set the resolver?
Secondly, when I attempt to retrieve my ILogger out of the kernel, as in these two lines of code:
var kernel = (IKernel) GlobalConfiguration.Configuration.DependencyResolver.GetService (typeof (IKernel));
return kernel.Get<ILoggerFactory> ().GetCurrentClassLogger ();
I receive an exception that no matching bindings are available,...the sort of standard "you asked for something we can't resolve" message.
So, I modified the RegisterServices method in NinjectWebCommon and added:
kernel.Load (new Ninject.Extensions.Logging.NLog2.NLogModule());
..and then I get a different error, "Another module (of type NLogModule) with the same name has already been loaded". Sure enough, I inspect the IKernel variable and there is already a binding for ILoggerFactory.
This confused me so i took that line back out, and inspected the IKernel variable without the explicit addition of the NLogModule, and I was flummoxed to see that there is a binding for 'ILoggerFactory' after all. So the NLogModule does seem to be registering itself automatically, it is present in the bindings collection, but when I attempt to retrieve it can't be resolved. What have I done wrong? Can someone tell me what the best practices are here? Should I have modified the 'CreateKernel' method at all, or was that a mistake? So much of this is supposed to be automatic, I don't know where to turn when it doesn't work...I know there's the notion of a dependency scope, but I'll admit I don't fully understand it. Any help would be terrific.
Thanks in advance.
- Tom