Passing Services using Dependency Injection and Factory Pattern in ASP.NET

18,868

There are a couple of errors in your approach:

Instead, your service should look as follows:

public class MyService
{
    private ILogger _logger;
    public MyService(ILogger logger)
    {
        _logger = logger;
    }
}

This dramatically simplifies all consumers that depend upon ILogger. This also means that getting the right ILogger for MyService 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:

services.AddTransient<MyService>(c => new MyService(
    BuildLogger(typeof(MyService).Name),
    c.GetRequiredService<ISomeOtherDependency>(),
    c.GetRequiredService<IYetAnotherOne>());
Share:
18,868
Hussein Salman
Author by

Hussein Salman

Engineering Manager &amp; Cloud-Native Architect, focusing on Kubernetes, Containers &amp; Microservices. Check out my youtube channel: https://www.youtube.com/channel/UCoAh8g6dmwXQUwKhkggUFIA

Updated on June 08, 2022

Comments

  • Hussein Salman
    Hussein Salman almost 2 years

    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?