1

I'm new to the Dependency Injection in ASP.NET Core 3.1, and I'm trying to create Singleton instances of my Repository classes using Reflection, but I can't get it to work.

Currently, the BookService uses the BookRepository from the DI:

public class BookService : IBookService
{
    private readonly IBookRepository _bookRepository;

    public BookService(IBookRepository bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public async Task<Book> GetById(string id)
    {
        var find = await _bookRepository.FindAsync(id);
        return find;
    }
}

It works because I added a singleton service to the container, with the following code (link to Microsoft Docs): services.AddSingleton<IBookRepository, BookRepository>();

I'm trying to achieve the same result using Reflection.

BookRepository

public class BookRepository : BaseRepository<Book>, IBookRepository
{
}

IBookRepository

public interface IBookRepository : IAsyncRepository<Book>
{
}

This is what I have so far:

// Get all classes implementing IAsyncRepository
var repositoryTypes = assembly.GetTypes()
    .Where(x => !x.IsInterface
        && x.GetInterface(typeof(IAsyncRepository<>).Name) != null);
        
foreach (var repositoryType in repositoryTypes)
{
   // Adds a singleton service of BookRepository
   services.AddSingleton(repositoryType);
}

But as you can see, the code above is adding only the BookRepository, missing to reference the IBookRepository interface, so it's throwing the following error:

System.ArgumentException: 'Cannot instantiate implementation type 'IBookRepository' for service type 'IBookRepository'.'


Do you know how can I do that?

**EDIT:** This is the implementation I made to solve the problem:

``` c#
public static class DependencyInjectionExtensions
{
    public static void AddApplicationServices(
        this IServiceCollection services)
    {
        var assembly = Assembly.GetExecutingAssembly();

        RegisterImplementationsOfServiceType(
            services, assembly, typeof(IService));
        RegisterImplementationsOfServiceType(
            services, assembly, typeof(IAsyncRepository<>));
    }

    private static void RegisterImplementationsOfServiceType(
        IServiceCollection services, Assembly assembly, Type type)
    {
        var implementationsType = assembly.GetTypes()
            .Where(x => !x.IsInterface && x.GetInterface(type.Name) != null);
            
        foreach (var implementationType in implementationsType)
        {
            var servicesType = implementationType.GetInterfaces()
                .Where(r => !r.Name.Contains(type.Name));
                
            foreach (var serviceType in servicesType)
            {
                services.AddSingleton(serviceType, implementationType);
            }
        }
    }
}
1
  • IMHO, define an attribute ServiceInterfaceAttribute, add it to IBookRepository, scan the assembly for any type implementing an interface with the attribute? That might simplify your dynamic configuration... Commented Feb 21, 2021 at 23:28

1 Answer 1

3

Something like this would work

// Get all classes implementing IAsyncRepository
var repositoryTypes = assembly.GetTypes().Where(x => !x.IsInterface &&  
x.GetInterface(typeof(IAsyncRepository<>).Name) != null);
foreach (var repositoryType in repositoryTypes)
{
    var type = repositoryType.UnderlyingSystemType;
    services.AddSingleton(type.GetInterface($"I{type.Name}"), type);
}

I'm not sure if there is a better way to get the interface type

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

3 Comments

this may work for the specific case of the OP and as long as the naming convention is followed ( I mean about IService for interface and Service for implementation) :) Generally it may fail. You can just get all the interfaces of the filtered types (using GetInterfaces) and register each pair of each interface & the type. That would cover all the pairs of interface & class and has a better result.
Thanks for the response! It worked! Hey @KingKing you meant like this? var interfacesType = repositoryType.GetInterfaces().Where(r => !r.Name.Contains(typeof(IAsyncRepository<>).Name)); so I can just loop the all interfaces of the class and add the singleton to the service: services.AddSingleton(interfaceType, repositoryType); what do you think?
@Gabriel that would try registering the services of IAsyncRepository so it will miss the interface like IBookRepository, actually you need a convention or rule to select the interfaces you want, as in your case I understand that IBookRepository is what need to be registered (not IAsyncRepository). If you don't have specific convention or rule to filter for the interfaces (from GetInterfaces()), then you can just register all with the implementation, it's no harm (with a little bit of extra memory consumed by the DI container).

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.