dependency-injectionasp.net-core-9.0c#-13.0

.Net Core 9 DI for dynamic instance creation and its required services


I have the following 2 classes. MyClass composes MyOtherClasses. Each of them requires different ILogger<foo>:

public class MyClass 
{
    private readonly ILogger<MyClass> _logger;
    private Dictionary<string, MyOtherClass> _instances;
    public MyClass(ILogger<MyClass> logger, int count)
    {
        _logger = logger;
        _instances = new Dictionary<string, SeatMap>();
    }
    public void Operate(string id, int var1, string var2, ...)
    {
        if (!_instances.ContainsKey(id))
            _instances.Add(id, new MyOtherClass(/* XXX */, var1, var2));
    }
}
public class MyOtherClass
{
    private int _var1;
    private string _var2;
    private readonly ILogger<MyOtherClass> _logger;
    public MyOtherClass(ILogger<MyOtherClass> logger, int var1, string var2)
    {
        _logger = logger;
        _var1 = var1;
        _var2 = var2;
    }
}

What's the best .Net Core C# way of achieving this instance creation? I am thinking of:

  1. Register and GetRequiredService<MyOtherClass>(). This would solve the ILogger<foo> but I doubt it would solve the other input parameters of the constructor.

  2. MyClass constructor uses ILoggerFactory as DI injected param and use that to create the required ILogger<foo> for both itself and MyOtherClass.


I currently resort to solution (2):

public class MyClass 
{
    private readonly ILoggerFactory _loggerFactory;
    private readonly ILogger<MyClass> _logger;
    private Dictionary<string, MyOtherClass> _instances;
    public MyClass(ILoggerFactory logger, int count)
    {
        _loggerFactory = logger;
        _logger = logger.CreateLogger<MyClass>();
        _instances = new Dictionary<string, SeatMap>();
    }
    public void Operate(string id, int var1, string var2, ...)
    {
        if (!_instances.ContainsKey(id))
            _instances.Add(id, new MyOtherClass(_loggerFactory.CreateLogger<MyOtherClass>(), var1, var2));
    }
}
public class MyOtherClass
{
    private int _var1;
    private string _var2;
    private readonly ILogger<MyOtherClass> _logger;
    public MyOtherClass(ILogger<MyOtherClass> logger, int var1, string var2)
    {
        _logger = logger;
        _var1 = var1;
        _var2 = var2;
    }
}

Solution

  • You can use the helper method ActivatorUtilities.CreateInstance() to create an object of a given class (in your case MyOtherClass), where all the required services are resolved with a given IServiceProvider instance. The remaining arguments must be provided via the parameters object array parameter. However, you need the IServiceProvider instance since the helper method must know where to get the services from.