19

I have following repository classes:

public class TestRepository : Repository<Test>
{
    private TestContext _context;

    public TestRepository(TestContext context) : base(context)
    {
        _context = context;
    }
}

public abstract class Repository<T> : IRepository<T> where T : Entity
{
    private TestContext _context;

    public Repository(TestContext context)
    {
        _context = context;
    }
    ...
}

public interface IRepository<T>    
{
    ...
}

How do I implement the dependency injection in ASP.NET Core in my Startup.cs?

I implemented it like this:

services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

But then I get following error:

Cannot instantiate implementation type 'Test.Domain.Repository1[T]' for service type 'Test.Domain.IRepository1[T]'.

3 Answers 3

31

Repository<T> is an abstract class, so you cannot register it as an implementation, because abstract class simply cannot be instantiated. Your registration would work fine if Repository<T> was not abstract.

If you cannot make repository class non-abstract, you can register specific implementation of your repository class:

services.AddScoped(typeof(IRepository<Test>), typeof(TestRepository));

This will correctly inject dependencies to your controller.

Sign up to request clarification or add additional context in comments.

2 Comments

You could also the generic AddScoped method, which is less verbose: services.AddScoped<IRepository<Test>, TestRepository>()
Note: if you register a generic instance, like services.AddScoped(typeof(IRepository<>), typeof(GenericRepository<>)), you can't also provide a specific instance that overrides the general one in specific circumstances. This generates an error "Open generic service type 'IRepository`1[T]' requires registering an open generic implementation type", which is incorrect seeing as how you have an open generic implementation registered.
11

I know this is very late but I am posting my solution here so that others can refer and use this. I have written some extensions to register all the derived types of generic interface.

public static List<TypeInfo> GetTypesAssignableTo(this Assembly assembly, Type compareType)
{
        var typeInfoList = assembly.DefinedTypes.Where(x => x.IsClass 
                            && !x.IsAbstract 
                            && x != compareType
                            && x.GetInterfaces()
                                    .Any(i => i.IsGenericType
                                            && i.GetGenericTypeDefinition() == compareType))?.ToList();

        return typeInfoList;
 }

public static void AddClassesAsImplementedInterface(
        this IServiceCollection services, 
        Assembly assembly, 
        Type compareType,
        ServiceLifetime lifetime = ServiceLifetime.Scoped)
 {
        assembly.GetTypesAssignableTo(compareType).ForEach((type) =>
        {
            foreach (var implementedInterface in type.ImplementedInterfaces)
            {
                switch (lifetime)
                {
                    case ServiceLifetime.Scoped:
                        services.AddScoped(implementedInterface, type);
                        break;
                    case ServiceLifetime.Singleton:
                        services.AddSingleton(implementedInterface, type);
                        break;
                    case ServiceLifetime.Transient:
                        services.AddTransient(implementedInterface, type);
                        break;
                }
            }
        });
}

In the startup class, you just register your generic interface like below.

services.AddClassesAsImplementedInterface(Assembly.GetEntryAssembly(), typeof(IRepository<>));

You can find the complete extension code in this Github repository.

Comments

-2

You can register an abstract class only as a service, not as implementation as @dotnetom said.

See the definitions below

 public abstract class BaseClass<T>
{

    public BaseClass()
    {
    }
}

public class DerivedClass : BaseClass<Entity>
{
    public DerivedClass() : base() { }
}

public class DerivedClass2<T> : BaseClass<T> where T: Entity
{
   
}

public class Entity
{

}

Controller:

public class WeatherForecastController : ControllerBase
    {
        ......

        public WeatherForecastController(BaseClass<Entity> baseClass)
        {
            
        }
         ...
}

If you inject them on this way:

 services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass));

you get this error when you are resolving your dependency:

Open generic service type 'BaseClass`1[T]' requires registering an open generic implementation type. (Parameter 'descriptors')

You should register the generic type or register the service and the implementation with the generic argument defined

Now this should work perfectly as well

services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass2<>));

or

services.AddScoped(typeof(BaseClass<Entity>), typeof(DerivedClass2<Entity>));

IMHO I prefer to go with interface definitions rather than abstract classes.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.