3

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;
    }
}
Steven
  • 166,672
  • 24
  • 332
  • 435
Javiseeker
  • 47
  • 1
  • 11

2 Answers2

1

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<>));
Steven
  • 166,672
  • 24
  • 332
  • 435
0

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.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132