在 .NET Core 中定义特定通用服务的注入服务
Define Injected service on specific generic services in .NET Core
我正在寻找一种在 .NET Core 中通过以下示例使用 DI 的正确方法。
我有 LoggerStandardService
继承自 ILogger
服务。
它很好地注入了服务(EntityRepository<ModelA>
、EntityRepository<ModelB>
),但我想定义另一个 LoggerCustomService
来注入一些特定的通用服务,例如 EntityRepository<ModelC>
这里是执行这个王者的代码。
public interface IEntityRepository<T> where T : class { }
public class EntityRepository<T> : IEntityRepository<T>
where T : class
{
public EntityRepository(IDbContext context, ILogger logger)
{
//Do some stuff
}
}
public interface ILogger { }
public class LoggerStandardService : ILogger { }
public class LoggerCustomService : ILogger { }
在Startup.cs中:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDbContext, DbContext>();
services.AddScoped<ILogger, LoggerStandardService>();
services.AddScoped<LoggerCustomService>();
services.AddScoped<IEntityRepository<ModelA>, EntityRepository<ModelA>>();
services.AddScoped<IEntityRepository<ModelB>, EntityRepository<ModelB>>();
services.AddScoped<IEntityRepository<ModelC>, EntityRepository<ModelC>>
(x =>
new EntityRepository<ModelC>(
x.GetRequiredService<IDbContext>(),
x.GetRequiredService<LoggerCustomService>()));
这是执行此操作的正确方法吗?避免在 EntityRepository<ModelC>
构造函数中定义所有其他注入服务。
您要完成的任务的正确术语是基于上下文的注入或上下文注入,您将依赖项的实现基于其上下文(例如,它的父项,如您的情况)。
Microsoft 的内置 DI 容器 (MS.DI) 对此没有很好的支持,这通常意味着您必须使用变通办法,就像您应用的变通办法一样。像您这样的解决方法的缺点是无法在通用类型上使用自动注册,例如:
services.AddScoped(typeof(IEntityRepository<>), typeof(EntityRepository<>));
通过此注册,您告诉 MS.DI 将 IEntityRepository<T>
的任何封闭通用版本映射到 EntityRepository<T>
的兼容封闭通用实现。它使您不必为 IEntityRepository<ModelA>
、IEntityRepository<ModelB>
、IEntityRepository<ModelC>
、IEntityRepository<ModelD>
等进行注册。此功能是许多 DI 容器具有的极其重要的功能,因为当您的应用程序中有很多模型时,它会在您的 DI 配置中节省大量维护工作。
但不幸的是,由于 MS.DI 的限制,您的情况很不幸。每个关闭的 IEntityRepository<T>
注册都必须显式完成,例如使用您已经展示的方法。
另一种选择是利用 ActivatorUtilities
class。这使得单个 EntityRepository<ModelC>
注册更易于维护,因为它允许您仅指定一个被覆盖的依赖项:
services.AddScoped<IEntityRepository<ModelC>>(x =>
ActivatorUtilities.CreateInstance<EntityRepository<ModelC>>(x,
x.GetRequiredService<LoggerCustomService>()));
ActivatorUtilities.CreateInstance<T>
允许创建提供的 T
的新实例,同时从提供的服务提供者 x
解析其构造函数的所有依赖项,除非显式提供依赖项,这使用第二个参数 x.GetRequiredService<LoggerCustomService>()
.
完成
我正在寻找一种在 .NET Core 中通过以下示例使用 DI 的正确方法。
我有 LoggerStandardService
继承自 ILogger
服务。
它很好地注入了服务(EntityRepository<ModelA>
、EntityRepository<ModelB>
),但我想定义另一个 LoggerCustomService
来注入一些特定的通用服务,例如 EntityRepository<ModelC>
这里是执行这个王者的代码。
public interface IEntityRepository<T> where T : class { }
public class EntityRepository<T> : IEntityRepository<T>
where T : class
{
public EntityRepository(IDbContext context, ILogger logger)
{
//Do some stuff
}
}
public interface ILogger { }
public class LoggerStandardService : ILogger { }
public class LoggerCustomService : ILogger { }
在Startup.cs中:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDbContext, DbContext>();
services.AddScoped<ILogger, LoggerStandardService>();
services.AddScoped<LoggerCustomService>();
services.AddScoped<IEntityRepository<ModelA>, EntityRepository<ModelA>>();
services.AddScoped<IEntityRepository<ModelB>, EntityRepository<ModelB>>();
services.AddScoped<IEntityRepository<ModelC>, EntityRepository<ModelC>>
(x =>
new EntityRepository<ModelC>(
x.GetRequiredService<IDbContext>(),
x.GetRequiredService<LoggerCustomService>()));
这是执行此操作的正确方法吗?避免在 EntityRepository<ModelC>
构造函数中定义所有其他注入服务。
您要完成的任务的正确术语是基于上下文的注入或上下文注入,您将依赖项的实现基于其上下文(例如,它的父项,如您的情况)。
Microsoft 的内置 DI 容器 (MS.DI) 对此没有很好的支持,这通常意味着您必须使用变通办法,就像您应用的变通办法一样。像您这样的解决方法的缺点是无法在通用类型上使用自动注册,例如:
services.AddScoped(typeof(IEntityRepository<>), typeof(EntityRepository<>));
通过此注册,您告诉 MS.DI 将 IEntityRepository<T>
的任何封闭通用版本映射到 EntityRepository<T>
的兼容封闭通用实现。它使您不必为 IEntityRepository<ModelA>
、IEntityRepository<ModelB>
、IEntityRepository<ModelC>
、IEntityRepository<ModelD>
等进行注册。此功能是许多 DI 容器具有的极其重要的功能,因为当您的应用程序中有很多模型时,它会在您的 DI 配置中节省大量维护工作。
但不幸的是,由于 MS.DI 的限制,您的情况很不幸。每个关闭的 IEntityRepository<T>
注册都必须显式完成,例如使用您已经展示的方法。
另一种选择是利用 ActivatorUtilities
class。这使得单个 EntityRepository<ModelC>
注册更易于维护,因为它允许您仅指定一个被覆盖的依赖项:
services.AddScoped<IEntityRepository<ModelC>>(x =>
ActivatorUtilities.CreateInstance<EntityRepository<ModelC>>(x,
x.GetRequiredService<LoggerCustomService>()));
ActivatorUtilities.CreateInstance<T>
允许创建提供的 T
的新实例,同时从提供的服务提供者 x
解析其构造函数的所有依赖项,除非显式提供依赖项,这使用第二个参数 x.GetRequiredService<LoggerCustomService>()
.