Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection resolution with constructors having multiple parameters whose values are determined at runtime .NET Core 3

As a reply to an earlier question (Accessing ILogger from non-Controller classes in Class Libary .NET Core 3), we can inject the dependent class into the controller. The DI Container resolves dependencies on registration of Transient services at the time of Startup. Hence if a ClassA is instantiated by a Controller, as a result of this mechanism, we can access ILogger in Class A.

Original question code sample:

public class Startup
{
    ...

    public void ConfigureServices(IServiceCollection services)
    {      
        services.AddLogging();
        services.AddTransient<ClassX>();

        ...
    }
}

public class ControllerB : ControllerBase
{
    private readonly ClassX classX;
    private readonly ILogger logger;

    public ControllerB(ClassX classX, ILogger<ControllerB> logger)
    {
        this.classX = classX;
        this.logger = logger;
    }

    ...
}

public class ClassX
{
   private readonly ILogger logger;

   public ClassX(ILogger<ClassX> logger)
   {
       this.logger = logger;
   }
}

Now I have a scenario as below, where the constructor of ClassX has multiple parameters:

public class ClassX
{
    private readonly ILogger logger;
    private int _num1;

    public ClassX(ILogger<ClassX> logger, int num1)
    {
        this.logger = logger;
        this.num1 = num1;
    }
}

Constructor of ClassX made available to .NET Core DI container through [ActivatorUtilitiesConstructor]:

[ActivatorUtilitiesConstructor]
public ClassX(int num)
{
    this.constructorNum = num;
}

So we need to inject the constructor parameters during DI resolution at Startup. I tried this

services.AddTransient<Func<int, ClassX>>((provider) =>
{
    return new Func<int, ClassX>((numParam) => new ClassX(numParam));
});

But this throws an error as we are not passing the ILogger.

How do I inject the ILogger as well as the constructor parameters at runtime through DI?

like image 441
Ashwin Hariharan Avatar asked Jan 25 '23 10:01

Ashwin Hariharan


1 Answers

For this scenario, you can use the provider parameter that's being passed into the factory function to resolve an instance of ILogger<ClassX> from the IoC container:

services.AddTransient<Func<int, ClassX>>((provider) =>
{
    return new Func<int, ClassX>((numParam) =>
        new ClassX(provider.GetRequiredService<ILogger<ClassX>>(), numParam));
});

provider here is an implementation of IServiceProvider. This example uses an extension method, GetRequiredService, to retrieve an instance of ILogger<ClassX>.

like image 123
Kirk Larkin Avatar answered Jan 28 '23 13:01

Kirk Larkin