Nov 272012
 

I love Ninject, and I love log4net. I tend to pull them in to any project that I’m working on. And Ninject provides great support through its Ninject.Extensions.Logging package for getting log4net loggers injected into your classes with very little work. But one thing always bugged me: you have to put an [Inject] attribute on every ILogger property that you want injected. I hate that, because it scatters Ninject all over your implementation classes, and as a general rule your classes should be agnostic toward whatever IoC container you happen to be using. So, I created the NinjectAutoLogging package to allow for automatically injecting ILogger properties without the need for the attribute.

Let’s look at some sample code that you would normally end up with if you use Ninject.Extensions.Logging:

public class ClassThatLogs
{
    [Inject]
    public ILogger Logger { get; set; }
 
    public void DoSomething()
    {
        Logger.Info("I have done something!");
    }
}
 
[TestFixture]
public class Tests
{
    [Test]
    public void Test()
    {
        BasicConfigurator.Configure();
        var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false },
            new Log4NetModule());
        kernel.Bind().ToSelf();
        kernel.Get().DoSomething();
    }
}

If you run that code, you will see that you get the “I have done something!” message from the logging class on the console. Almost perfect, but let’s get rid of that pesky [Inject]. Here is the same code, but using the NinjectAutoLogging module.

public class ClassThatLogs
{
    public ILogger Logger { get; set; }
 
    public void DoSomething()
    {
        Logger.Info("I have done something!");
    }
}
 
[TestFixture]
public class Tests
{
    [Test]
    public void Test()
    {
        BasicConfigurator.Configure();
        var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false },
            new Log4NetModule(),
            new AutomaticLoggingInjectionModule());
        kernel.Bind().ToSelf();
        kernel.Get().DoSomething();
    }
}

We have removed the [Inject] and added an AutomaticLoggingInjectionModule to our kernel. That is all there is to it. Now, any classes that have a public property of type Ninject.Extensions.Logging.ILogger will be automatically injected.

There is one final problem, though. If we tried to test the DoSomething method outside of Ninject, it would crash with a NullReferenceException when it tried to log. To fix this, I included a NullLogger implementation in the package as well. You can use it like this:

public class ClassThatLogs
{
    public ILogger Logger { get; set; }
 
    public ClassThatLogs()
    {
        Logger = new NullLogger();
    }
 
    public void DoSomething()
    {
        Logger.Info("I have done something!");
    }
}

Now, when you instatiate this class directly from a test, the logging calls will go to the NullLogger and the code will happily keep running. But, when Ninject instatiates the class, it will still automatically inject a real logger.

I tried to contact the Ninject authors to get this stuff included in the Ninject.Extensions.Logging package instead of publishing something separately. but I didn’t hear anything for a couple weeks. If you guys end up seeing this, and you’d like to include, just let me know and I’ll hand it over.

If you want to see the source code (it is pretty simple), you can find it over at BitBucket.

  4 Responses to “Introducing NinjectAutoLogging”

  1. This looks great and exactly what I am looking for. Is there any chance you can add a version of the assembly for .net 4 to the nuget package?

    • Hi Andrew. Glad it was a help. Sorry I didn’t respond sooner. I don’t have the bandwidth at the moment to add support for older .NET versions. However, it should be as simple as getting the code and recompiling it.

  2. That’s pretty cool. However, one still must reference the Ninject library wherever you want to use ILogger, which is unfortunate.

    • Hi David,

      I agree that is an unfortunate piece. If it is a concern, you could always create your own version of ILogger that just sits in front of the actual Ninject ILogger, akin to the adapter pattern. This makes it so that your code doesn’t have to reference Ninject at all. I’ve never found this to be a big problem, so I usually just live with the reference.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>