Struggling to get NLog and Ninject to cooperate

372 views
Skip to first unread message

Tom Wyckoff

unread,
Feb 10, 2014, 1:44:41 PM2/10/14
to nin...@googlegroups.com
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 



Tom Wyckoff

unread,
Feb 10, 2014, 4:36:54 PM2/10/14
to nin...@googlegroups.com
Well, this seems rather obvious in retrospect, but in the spirit of posterity - I had two projects working together to do this, and in the actual API project (as opposed to a library function DLL which had a lot of the base functionality) I hadn't included the Ninject.Extensions.Logging.NLog2 package, since I was working strictly with the abstract interfaces that were all defined in Ninject.Extensions.Logging (so as to remain loosely coupled, not bound to NLog). Turns out that although I never referenced any of the NLog specific classes, that DLL is required for this to work. It was one of those things that jumped out at me after I went to the gym and came back and looked at it again a few hours later.

HTH.
Reply all
Reply to author
Forward
0 new messages