Over a million developers have joined DZone.

A Generic Logger Factory Facade for Classic ASP.NET

DZone's Guide to

A Generic Logger Factory Facade for Classic ASP.NET

A web developer discusses when creating logger system for a web application makes sense, and how to do so in an ASP.NET-based web application.

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

ASP.NET Core already has this feature. There is a ILoggerFactory to create a logger. You are able to inject the ILoggerFactory to your component (Controller, Service, etc.) and to create a named logger out of it. During testing you are able to replace this factory with a mock, to not test the logger as well, and to not have an additional dependency to setup.

Recently, we had the same requirement in a classic ASP.NET project, where we used Ninject to enable dependency injection and log4net to log all the stuff we did and all the exceptions. One important requirement was creating a named logger per component.

Creating Named Loggers

Usually log4net gets created inside the components as a private static instance:

private static readonly ILog _logger = LogManager.GetLogger(typeof(HomeController)); 

There already is a static factory method to create a named logger. Unfortunately, this isn't really testable anymore and we need a different solution.

We could create a bunch of named loggers in advance and register them to Ninject, which obviously is not the right solution. We need to have a more generic solution. We figured out two different solutions:

// would work well
public MyComponent(ILoggerFactory loggerFactory)
    _loggerA = loggerFactory.GetLogger(typeof(MyComponent));
    _loggerB = loggerFactory.GetLogger("MyComponent");
    _loggerC = loggerFactory.GetLogger<MyComponent>();
// even more elegant
public MyComponent(
    ILoggerFactory<MyComponent> loggerFactoryA
    ILoggerFactory<MyComponent> loggerFactoryB)
    _loggerA = loggerFactoryA.GetLogger();
    _loggerB = loggerFactoryB.GetLogger();

We decided to go with the second approach, which is a simpler solution. This needs a dependency injection container that supports open generics like Ninject, Autofac, and LightCore.

Implementing the LoggerFactory

Using Ninject the binding of open generics looks like this:


This binding creates an instance of LoggerFactory<T> using the requested generic argument. If I request an ILoggerFactory<HomeController>, Ninject creates an instance of LoggerFactory<HomeController>.

We register this as a singleton to reuse the ILog instances as we would do using the usual way to create the ILog instance in a private static variable.

The implementation of the LoggerFactory is pretty easy. We use the generic argument to create the log4net ILog instance:

public interface ILoggerFactory<T>
ILog GetLogger();

public class LoggerFactory<T> : ILoggerFactory<T>
    private ILog _logger;
    public ILog GetLogger()
        if (_logger == null)
            var type = typeof(T);
            _logger = LogManager.GetLogger(typeof(T));
        return _logger;

We need to ensure the logger is created before creating a new one. Because Ninject creates a new instance of the LoggerFactory per generic argument, the LoggerFactory don't need to care about the different loggers. It just stores a single specific logger.


Now we are able to create one or more named loggers per component.

What we cannot do using this approach is to create individually named loggers, using a specific string as a name. There is a type needed that gets passed as a generic argument. So every time we need an individual named logger we need to create a specific type. In our case, this is not a big problem.

If you don't like to create types just to create individually named loggers, feel free to implement a non-genericLoggerFactory and make a generic GetLogger method as well as a GetLogger method that accepts strings as logger names.

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

web dev ,web application development ,logging ,asp.net

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}