Proper use of ILogger<> in an abstract Factory

144 Views Asked by At

I have the following scenario in .NET/C#: I have a IMyService that is created via an IMyServiceFactory.

public interface IMyServiceFactory
{
    public IMyService CreateMyService(string something);
}

public interface IMyService
{
    // Some methods
}

My concrete IMyServiceFactory takes an ILogger _logger via ctor injection and creates a MyService, that also requires a logger via ctor injection:

public class MyServiceFactory : IMyServiceFactory
{
    private readonly ILogger<MyServiceFactory> _logger;

    public MyServiceFactory(ILogger<MyServiceFactory> logger)
    {
        _logger = logger;
    }

    public IMyService CreateMyService(string something)
    {
        return new MyService(/* ??? */);
    }
}

public class MyService 
{
    public MyService(ILogger<MyService> logger)
    { /* ... */ }
}

How do I get an instance of ILogger into my ctor call? What is the proper way to do it? In my case, IMyServiceFactory is initialized in Startup.cs.

2

There are 2 best solutions below

0
Krishna Varma On

Update the MyServiceFactory class to accept an IServiceProvider parameter in the constructor:

public class MyServiceFactory : IMyServiceFactory
{
    private readonly ILogger<MyServiceFactory> _logger;
    private readonly IServiceProvider _serviceProvider;

    public MyServiceFactory(ILogger<MyServiceFactory> logger, IServiceProvider serviceProvider)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
    }

    public IMyService CreateMyService(string something)
    {
        var logger = _serviceProvider.GetService<ILogger<MyService>>();
        return new MyService(logger);
    }
}

In your Startup.cs file, register the MyServiceFactory and MyService types with the dependency injection container:

public void ConfigureServices(IServiceCollection services)
{
    // Other service registrations...

    services.AddScoped<IMyServiceFactory, MyServiceFactory>();
    services.AddScoped<IMyService, MyService>();
}

In your Startup.cs file, ensure that the ILogger is registered correctly. The ILogger is typically registered automatically for classes like controllers, but you'll need to register it explicitly for MyService and MyServiceFactory since they're not controller classes:

public void ConfigureServices(IServiceCollection services)
{
    // Other service registrations...

    services.AddScoped<IMyServiceFactory, MyServiceFactory>();
    services.AddScoped<IMyService, MyService>();

    services.AddLogging();
}
0
Artur On

Use ILoggerFactory:

public class MyServiceFactory : IMyServiceFactory
{
    private readonly ILoggerFactory _loggerFactory;
    private readonly ILogger<MyServiceFactory> _logger;

    public MyServiceFactory(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
        _logger = loggerFactory.CreateLogger<MyServiceFactory>();
    }

    public IMyService CreateMyService(string something)
    {
        return new MyService(_loggerFactory.CreateLogger<MyService>());
    }
}

Also, consider using this factory implementation.