简体   繁体   English

如何在 ASP.NET Core 中注入泛型的依赖项

[英]How to inject dependencies of generics in ASP.NET Core

I have following repository classes:我有以下存储库类:

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

How do I implement the dependency injection in ASP.NET Core in my Startup.cs ?如何在Startup.cs ASP.NET Core 中实现依赖注入?

I implemented it like this:我是这样实现的:

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

But then I get following error:但后来我收到以下错误:

Cannot instantiate implementation type 'Test.Domain.Repository 1[T]' for service type 'Test.Domain.IRepository 1[T]'.无法1[T]' for service type 'Test.Domain.IRepository 1[T]”实例化实现类型“ 1[T]' for service type 'Test.Domain.IRepository 1[T]”。

Repository<T> is an abstract class, so you cannot register it as an implementation, because abstract class simply cannot be instantiated. Repository<T>是一个抽象类,所以你不能将它注册为一个实现,因为抽象类根本不能被实例化。 Your registration would work fine if Repository<T> was not abstract.如果Repository<T>不是抽象的,您的注册就可以正常工作。

If you cannot make repository class non-abstract, you can register specific implementation of your repository class:如果您不能使存储库类成为非抽象类,则可以注册存储库类的特定实现:

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

This will correctly inject dependencies to your controller.这将正确地将依赖项注入您的控制器。

I know this is very late but I am posting my solution here so that others can refer and use this.我知道这已经很晚了,但我在这里发布了我的解决方案,以便其他人可以参考和使用它。 I have written some extensions to register all the derived types of generic interface.我编写了一些扩展来注册泛型接口的所有派生类型。

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

In the startup class, you just register your generic interface like below.在启动类中,您只需注册您的通用接口,如下所示。

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

You can find the complete extension code in this Github repository.您可以在此Github存储库中找到完整的扩展代码。

You can register an abstract class only as a service , not as implementation as @dotnetom said.您只能将抽象类注册为服务,而不是@dotnetom 所说的实现

See the definitions below请参阅下面的定义

 public abstract class BaseClass<T>
{

    public BaseClass()
    {
    }
}

public class DerivedClass : BaseClass<Entity>
{
    public DerivedClass() : base() { }
}

public class DerivedClass2<T> : BaseClass<T> where T: Entity
{
   
}

public class Entity
{

}

Controller:控制器:

public class WeatherForecastController : ControllerBase
    {
        ......

        public WeatherForecastController(BaseClass<Entity> baseClass)
        {
            
        }
         ...
}

If you inject them on this way:如果您以这种方式注入它们:

 services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass));

you get this error when you are resolving your dependency:解决依赖项时会收到此错误:

Open generic service type 'BaseClass`1[T]' requires registering an open generic implementation type.开放的通用服务类型“BaseClass`1[T]”需要注册一个开放的通用实现类型。 (Parameter 'descriptors') (参数“描述符”)

You should register the generic type or register the service and the implementation with the generic argument defined您应该注册泛型类型或使用定义的泛型参数注册服务和实现

Now this should work perfectly as well现在这也应该可以完美运行

services.AddScoped(typeof(BaseClass<>), typeof(DerivedClass2<>));

or

services.AddScoped(typeof(BaseClass<Entity>), typeof(DerivedClass2<Entity>));

IMHO I prefer to go with interface definitions rather than abstract classes.恕我直言,我更喜欢使用接口定义而不是抽象类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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