Casey Charlton wrote a good post about logging with Castle Windsor, the logging facility and log4net.  I've been tinkertankering around with Ninject so I decided to see if I could get it working as nicely.

Ivan Carrero wrote about a few posts about logging with Ninject, but newerish Ninject 1.0 features have enabled us to write code more like Casey's:

public class Service : IService
{
    private ILogger logger;

    [Inject]
    public ILogger Logger
    {
        get
        {
            if (logger == null) logger = NullLogger.Instance;
            return logger;
        }
        set { logger = value; }
    }

    public void SomeLogic()
    {
        Logger.Info("some logic performed");
    }
}

Using Ninject's Log4net integration

Ninject integrates very nicely with Log4net and NLog by providing modules suited for their use, and the Ninject.Core.Logging namespace contains ILogger and some other stuff.  Configure log4net, add the modules to the Ninject kernel and off you go.

var module = new InlineModule(m => m.Bind<IService>().To<Service>());
using (var kernel = new StandardKernel(module, new Log4netModule()))
{
    var mine = kernel.Get<IService>();
    mine.SomeLogic();
}

outputs a nice log message:

2008-06-20 12:32:31,759 [TestRunnerThread] INFO  Example.Service - some logic performed

Logging with AutoWiring [Inject]

You don't have to use that Inject attribute in order to take advantage of Ninject's services.   I don't like these guys on my code unless I have a better reason than supporting some tool.  I think it's mostly a personal preference, but I've found myself embroiled in a constant struggle to be flexible, so it just works for me to get rid of any artifacts that could require later attention in my situation.  Anyway, I wanted to get this example working just like Casey's.  And to do this with Ninject, you have to use the auto-wiring extension.

One problem is that AutoWiringModule attempts to inject and execute every method, so I had to customize it a little to use the StandardMethodHeuristic instead of the auto-wiring one.  This was very easy and is a good example of how Ninject is easily customized.

Another problem (which I submitted as an issue to the Ninject JIRA), is that the Log4NetModule doesn't bind ILogger to Log4NetLogger - so when the AutoWirer scans the Service class it won't inject the Logger property. 

That's fixed pretty easily as well, and the code for both modifications and the new client code is below:

public class Modules
{
    public static IModule AutoWiringStandardMethod = new AutoWiringStandardMethodModule();
    public static IModule Default = new InlineModule(m => m.Bind<IService>().To<Service>());
    public static IModule Logging = new LoggingModule();
}

public class AutoWiringStandardMethodModule : StandardModule
{
    public override void BeforeLoad()
    {
        Kernel.Components.Connect<IConstructorHeuristic>(new AutoWiringConstructorHeuristic());
        Kernel.Components.Connect<IPropertyHeuristic>(new AutoWiringPropertyHeuristic());
        Kernel.Components.Connect<IMethodHeuristic>(new StandardMethodHeuristic());
        Kernel.Components.Connect<IFieldHeuristic>(new AutoWiringFieldHeuristic());
    }

    public override void Load() {}
}

public class LoggingModule : StandardModule
{
    public override void BeforeLoad()
    {
        Kernel.Components.Connect<ILoggerFactory>(new Log4netLoggerFactory());
    }

    public override void Load()
    {
        Bind<ILogger>().To<Log4netLogger>();
    }
}

using (var kernel = new StandardKernel(
    Modules.Default,
    Modules.AutoWiringStandardMethod,
    Modules.Logging))
{
    var mine = kernel.Get<IService>();
    mine.SomeLogic();
}

My feelings about Ninject are really positive.  It's a pleasure to work with it and a masterfully branded open source project that has serious potential to overtake the big names in .NET dependency injection.  I particularly abhor XML configuration and Ninject has a really comfortable API that lets me skate that.  1.0 just came out!

Code sample