Injecting primitive type in constructor of generic type using Microsoft DI

1.5k Views Asked by At

I'm trying to use dependency injection to add a generic service that has constructor parameters. I Need to implement this, generically:

host.Services.AddSingleton<IService>(x => 
    new Service(x.GetRequiredService<IOtherService>(),
                x.GetRequiredService<IAnotherOne>(), 
                ""));

This is what I have working with open generics:

host.Services.AddSingleton(typeof(IGenericClass<>), typeof(GenericClass<>));

I have not been able to add constructor params with opengenerics. This is the class I want to add DI:

public class GenericClass<T> : IGenericClass<T> where T : class, new()
{
    private readonly string _connectionString;
    private readonly IGenericClass2<T> _anotherGenericInterface;
    private readonly IInterface _anotherInterface;
    public GenericClass(
        string connectionString,
        IGenericClass2<T> anotherGenericInterface,
        IInterface anotherInterface)
    {
        _connectionString = connectionString ??
            throw new ArgumentNullException(nameof(connectionString));
        _executer = anotherGenericInterface;
        _sproc = anotherInterface;
    }
}
2

There are 2 best solutions below

0
Steven On BEST ANSWER

With MS.DI, it's impossible to construct an open-generic registration using a factory method, just as you did with the IService registration.

The solution here is to wrap all primitive constructor values into a Parameter Object, so the DI Container can resolve it as well. For instance:

// Parameter Object that wraps the primitive constructor arguments
public class GenericClassSettings
{
    public readonly string ConnectionString;
    
    public GenericClassSettings(string connectionString)
    {
        this.ConnectionString =
            connectionString ?? throw new ArgumentNullExcpetion();
    }
}

The GenericClass<T>'s constructor can now depend on the new Parameter Object:

public GenericClass(
    GenericClassSettings settings,
    IGenericClass2<T> anotherGenericInterface,
    IInterface anotherInterface)
{
    _connectionString = settings.ConnectionString;
    _executer = anotherGenericInterface;
    _sproc = anotherInterface;
}

This allows you to register both the new parameter object and the open-generic class:

host.Services.AddSingleton(new GenericClassSettings("my connection string"));

host.Services.AddSingleton(typeof(IGenericClass<>), typeof(GenericClass<>));
0
Oleksandr Tsvirkun On

You cannot pass parameters to the constructor using Microsoft DI. But factory methods allow to do it. If you want to pass type string to this constructor as a parameter you need to register string as a service - but this action can cause a lot of errors because a lot of services can have constructors string params. So I advise you to use Options pattern to pass a parameter like a connection string.