簡體   English   中英

如何在 ASP.NET Core 中注入泛型的依賴項

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

我有以下存儲庫類:

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.NET Core 中實現依賴注入?

我是這樣實現的:

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

但后來我收到以下錯誤:

無法1[T]' for service type 'Test.Domain.IRepository 1[T]”實例化實現類型“ 1[T]' for service type 'Test.Domain.IRepository 1[T]”。

Repository<T>是一個抽象類,所以你不能將它注冊為一個實現,因為抽象類根本不能被實例化。 如果Repository<T>不是抽象的,您的注冊就可以正常工作。

如果您不能使存儲庫類成為非抽象類,則可以注冊存儲庫類的特定實現:

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

這將正確地將依賴項注入您的控制器。

我知道這已經很晚了,但我在這里發布了我的解決方案,以便其他人可以參考和使用它。 我編寫了一些擴展來注冊泛型接口的所有派生類型。

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存儲庫中找到完整的擴展代碼。

您只能將抽象類注冊為服務,而不是@dotnetom 所說的實現

請參閱下面的定義

 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
{

}

控制器:

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

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

如果您以這種方式注入它們:

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

解決依賴項時會收到此錯誤:

開放的通用服務類型“BaseClass`1[T]”需要注冊一個開放的通用實現類型。 (參數“描述符”)

您應該注冊泛型類型或使用定義的泛型參數注冊服務和實現

現在這也應該可以完美運行

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

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

恕我直言,我更喜歡使用接口定義而不是抽象類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM