如何使用反射在 ASP.NET 核心中用自己的接口注册多个实现?

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

我是 ASP.NET Core 3.1 中的依赖注入的新手,我正在尝试使用反射创建我的存储库 类 的单例实例,但我无法将其用于工作。

目前,BookService 使用来自 DI 的 BookRepository

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

之所以有效,是因为我使用以下代码 (link to Microsoft Docs) 向容器添加了单例服务: services.AddSingleton<IBookRepository, BookRepository>();

我正在尝试使用反射实现相同的结果。

BookRepository

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

IBookRepository

public interface IBookRepository : IAsyncRepository<Book>
{
}

这是我目前拥有的:

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

但是如您所见,上面的代码仅添加了 BookRepository,没有引用 IBookRepository 接口,因此它抛出了以下错误:

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

像这样的东西会起作用

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

不知道有没有更好的获取接口类型的方法