web-dev-qa-db-ja.com

ASP.NETCoreでジェネリックの依存性を注入する方法

次のリポジトリクラスがあります。

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>    
{
    ...
}

Startup.csのASP.NETCoreに依存性注入を実装するにはどうすればよいですか?

私はそれを次のように実装しました:

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

しかし、次のエラーが発生します。

実装タイプ 'Test.Domain.Repository1[T]' for service type 'Test.Domain.IRepository1 [T]'をインスタンス化できません。

11
Palmi

Repository<T>は抽象クラスであるため、抽象クラスをインスタンス化できないため、実装として登録することはできません。 Repository<T>が抽象的でない場合、登録は正常に機能します。

リポジトリクラスを非抽象化できない場合は、リポジトリクラスの特定の実装を登録できます。

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

これにより、依存関係がコントローラーに正しく挿入されます。

19
dotnetom

私はこれが非常に遅いことを知っていますが、他の人がこれを参照して使用できるように、ここに私の解決策を投稿しています。派生型のジェネリックインターフェイスをすべて登録するための拡張機能をいくつか作成しました。

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

スタートアップクラスでは、以下のようにジェネリックインターフェイスを登録するだけです。

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

完全な拡張コードは、この Github リポジトリにあります。

4
Arul