Common Logging, Log4Net, Castle Windsor and ASP.NET MVC

By Ugo Lattanzi on July 11th , 2012 in .NET aspnetmvc | comments

Share On Google Share On Facebook Share On Twitter

It sounds like a cocktail and really it is! One of the first things I noticed in ASP.NET MVC 4 is the package Common.Logging.

This package is available on NuGet (thanks again for Nuget) and includes a library; the library name is the same of the package and is an abstraction of the principal logging frameworks.

Why is so useful this library? The answer is really simple, because your packages don’t have the reference to Log4Net, NLog, Elmah and Enterprise Library. It is really important because makes you able to change or update the log framework without recompile all your projects. Really I did the same thing in Dexter as you can see here the contract and here the concrete implementation using Log4Net.

If you like that approach, whether or not you're using ASP.NET MVC, you have to install the package running that command:

and, in the “host” project you have to reference the concrete implementation you prefer:

From now, everywhere you want to log something, you have to create the logger and then use it: csharp using Common.Logging; ... ILog log = LogManager.GetCurrentClassLogger(); log.Debug("hello world"); The problem of this code is the repetitiveness. In every class you have to create the logger before use it. Ok it could be static but is already boring. Fortunately ASP.NET MVC has a good architecture and allows us to use the dependency injection (DI from now), so we can inject the logger into the constructor of our controllers:
public class HomeController : ControllerBase {
    ILog logger;
    public HomeController(ILog logger){
        this.logger = logger;
    }
}

The next step I want to analyze in this post is the registration of ILog. Typically, in the most DI frameworks for a registration, want the interface, the implementation and the lifecycle, so something like this: csharp public class DiRegister{ public void Register(){ //..... container.Register(typeof(ILog), LogManager.GetCurrentClassLogger(), LifeCycle.Singleton); } }

The problem of that approach is in LogManager.GetCurrentClassLogger().This method returns an instance of ILog for the current class, which is the class where you are registering your dependency: for this reason, this is a wrong behavior.

What does it mean? It’s simple. If you got an error inside the HomeController and you catch and Log it, you like to see that this error comes from the HomeController and not from the DI registration class.

The class LogManager has LogManager.GetLogger() method that accept also the logger name. You have to create a class that retrieves the correct name (HomeController in our example) and injects the Logger using the right name.

With Castle Windsor you have to create and register a SubDependencyResolver (you can do the same with the most DI frameworks) implementing the interface ISubDependencyResolver like in the code below:

public class LoggerSubDependencyResolver : ISubDependencyResolver
{
  public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,DependencyModel dependency)
  {
    return dependency.TargetType == typeof (ILog);
  }


public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,DependencyModel dependency)
  {
    if (CanResolve(context, contextHandlerResolver, model, dependency))
    {
      if (dependency.TargetType == typeof (ILog))
      {
        return LogManager.GetLogger(model.Implementation);
      }
    }
    return null;
  }
}

Now you have to register your SubDependencyResolver in Castle Container and test it:

container.Kernel.Resolver.AddSubResolver(new LoggerSubDependencyResolver());

Summarizing, you can inject a Log without dependencies, only using NuGet and few c# code lines. No Dependency, No new() keyword.

That’s awesome!