简体   繁体   中英

How to register multiple implementations with its own interface in ASP.NET Core using Reflection?

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);
            }
        }
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM