Я новичок в внедрении зависимостей в ASP.NET Core 3.1, и я пытаюсь создать экземпляры Singleton моих классов репозитория с помощью Reflection, но не могу заставить его работать.

В настоящее время BookService использует BookRepository из 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;
    }
}

Это работает, потому что я добавил в контейнер одноэлементную службу со следующим кодом (ссылка на Microsoft Docs): services.AddSingleton<IBookRepository, BookRepository>();

Я пытаюсь добиться того же результата с помощью Reflection.

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: «Невозможно создать экземпляр типа реализации IBookRepository для типа службы 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
Gabriel 22 Фев 2021 в 00:06

1 ответ

Лучший ответ

Примерно так будет работать

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

Я не уверен, есть ли лучший способ получить тип интерфейса

1
CaveCoder 21 Фев 2021 в 21:31