I am using ASP.NET Core, I know that such Logging mechanism is already provided by the framework, but using this to illustrate my problem.
I am using kind of Factory pattern to build the Logger class, since I don't know the type of logging (because it is stored in DB).
The ILogger Contract
Log(string msg)
Then LoggerFactory will return an ILogger after creating a Logger based on param passed from DB:
public class LoggerFactory
{
public static Contracts.ILogger BuildLogger(LogType type)
{
return GetLogger(type);
}
//other code is omitted, GetLogger will return an implementation of the related logger
Now, when I need to use the Logger I have to do it in this way:
public class MyService
{
private ILogger _logger
public MyService()
{
_logger = LoggerFactory.BuildLogger("myType");
}
But, I intend to keep my classes without any instantiation, I need to use Constructor DI in MyService and I need to inject all the dependencies on Startup:
services.AddTransient<Contracts.ILogger, LoggerFactory.BuildLogger("param") > ();
But this will not work this we need to pass a concrete implementation. How to make that work using DI, is there a better approach for implementing that?
There are a couple of errors in your approach:
LoggerFactory
type which is a Dependency Injection Principle violation.ILogger
is the real service that your consumer depends upon. This makes the system harder to test, harder to maintain, and complicates object graph analysis.Instead, your service should look as follows:
This dramatically simplifies all consumers that depend upon
ILogger
. This also means that getting the rightILogger
forMyService
becomes a responsibility of the Composition Root, which is the correct place to have this knowledge.It does mean however that you might need to move away from the built-in DI container of ASP.NET Core to a more feature rich DI library, because the built-in container is not capable of making a context aware registration for
ILogger
while having the library auto-wire other constructor dependencies as well.With the ASP.NET Core DI container, you can only hand-wire your services using a delegate. For instance: