I'm working with a project which utilizes Simple Injector as dependency injector. On the other hand, this project uses Microsoft.Extensions.Logging in order to log the events that occurs in certain classes.
My technical issue is pretty simple to explain.
I want to register in my DI the ILogger independently of the class T which is being invoked, but I DO NEED to do it from my ILoggerFactory.CreateLogger<T>()
method because this gets the logger configuration using Microsoft.Extensions.Configuration
.
I need to use something like this in order to instance my logger:
private Microsoft.Extensions.Logging.ILogger CreateLogger<T>()
{
var factory = this.ResolveService<ILoggerFactory>();
var logger = factory.CreateLogger<T>();
return logger;
}
I could achieve the injection by doing:
Container.Register(typeof(ILogger<>), typeof(Logger<>));
And this allows us to resolve something like:
public class SomeApiController : ApiController
{
public SomeApiController(ILogger<SomeApiController> logger)
{
//logger is well instantiated, but doesn't got the configuration
logger.LogInformation("test log.");
}
}
But as I said, this does it without passing through the configuration obtained from the Microsoft.Extensions.Logging.ILoggerFactory
class, so this isn't useful.
Is there a way to register ILogger<T>
by using my CreateLogger<T>
?
Use the following registrations:
Or, in case you are integrating Simple Injector into a generic host or ASP.NET Core application, make use of the .AddLogging() extension method to even inject a non-generic
ILogger
into your application components, as demonstrates in this ASP.NET CoreStartup
class:For a full example, see the ASP.NET Core and ASP.NET Core MVC Integration Guide.
Letting application components depend on
ILogger
instead ofILogger<T>
, makes your code simpler, easier to test, and less error prone. If you're using Simple Injector without Service Collection integration (as the previous example showed, you can use the following registration to let Simple Injector ensure the correctLogger<T>
is still injected whenever anILogger
is injected:This ensures that every application component gets its own
Logger<T>
instance, whereT
is the type of the component the logger is injected into. Take the following class for example that depends onILogger
:The above registration will ensure that
ComponentA
is injected with aLogger<ComponentA>
, even though it simply depends onILogger
and not onILogger<T>
.You can stop reading here if the above suits your needs... or continue reading if you're interested in a more SOLID solution.
A SOLID solution
Instead of letting application components depend on the framework-defined
ILogger
abstraction, you could also choose to define an application-specific logger abstraction, as prescribed by the Dependency Inversion Principle (DIP).The DIP states that abstractions should be defined by the application itself—this means you define your own logger abstraction (also see this for an explanation of why you want to do this) and on top of that you build an adapter, much like described here. You can simply derive your generic adapter from the described
MicrosoftLoggingAdapter
as follows:Using this generic adapter, you can configure Simple Injector as follows: