.NET 8依赖注入:注入特定泛型IValidator时无关实例被初始化求助
我使用.NET 8搭配9.0版本的Microsoft.Extensions.DependencyInjection。我有一组实现IValidator<in TModel, in TContext>接口的类,均通过services.AddScoped<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>, WebstoreIdIsValid>();注册到服务容器。之后在另一服务的构造函数中,以IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> validators为参数注入这些服务(需要多实例)。但问题是,每当注入该集合时,所有带有完全不同泛型参数的IValidator<>实现都会被实例化。由于这类实现数量多且各自依赖复杂,造成了显著性能开销。请问我操作有误导致无关类被初始化?若操作无误,该行为的目的是什么,如何规避?
问题原因
你没有操作错误,这是.NET依赖注入容器的默认行为。当请求IEnumerable<T>时,容器会扫描所有已注册的服务,只要服务类型与T属于同一个开放泛型接口(即IValidator<,>),就会被纳入集合,即便它们的泛型参数完全不同。这个设计是为了简化开放泛型服务的批量注入场景,但在你的场景下会引发不必要的实例化开销。
规避方案
方案一:使用标记接口缩小范围
为特定泛型组合的验证器创建专属标记接口,让容器精准匹配目标服务:
// 定义专用标记接口,继承目标泛型接口 public interface IWebStoreItemValidator : IValidator<WebStoreItemValidate, WebStoreItemValidationContext> { } // 修改验证器实现类,继承标记接口 public class WebstoreIdIsValid : IWebStoreItemValidator { // 原有验证逻辑保持不变 } // 注册时使用标记接口 services.AddScoped<IWebStoreItemValidator, WebstoreIdIsValid>(); // 注入时直接请求标记接口的集合 public class YourService { public YourService(IEnumerable<IWebStoreItemValidator> validators) { // 仅获取实现IWebStoreItemValidator的实例,无关验证器不会被实例化 } }
该方案最直观,通过强类型约束彻底避免无关服务的实例化。
方案二:使用键控服务(.NET 8+)
注册时为目标验证器指定唯一键,注入时按键筛选:
// 注册时指定键 services.AddKeyedScoped<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>, WebstoreIdIsValid>("WebStoreItem"); // 注入时通过IServiceProvider获取键控服务 public class YourService { private readonly IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> _validators; public YourService(IServiceProvider serviceProvider) { _validators = serviceProvider.GetKeyedServices<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>>("WebStoreItem"); } }
此方案利用.NET 8新增的键控服务特性,精准获取指定组的验证器,无需遍历所有同开放泛型的服务。
方案三:自定义扩展方法精准获取
实现IServiceProvider扩展方法,直接获取指定闭包泛型的服务集合:
public static class ValidatorServiceExtensions { public static IEnumerable<IValidator<TModel, TContext>> GetValidators<TModel, TContext>(this IServiceProvider provider) { return provider.GetServices(typeof(IValidator<TModel, TContext>)) .Cast<IValidator<TModel, TContext>>(); } } // 注入时使用扩展方法 public class YourService { private readonly IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> _validators; public YourService(IServiceProvider serviceProvider) { _validators = serviceProvider.GetValidators<WebStoreItemValidate, WebStoreItemValidationContext>(); } }
该方法通过GetServices(Type)的精准匹配,仅实例化并返回目标泛型参数的验证器,不会触发其他无关服务的创建。
内容的提问来源于stack exchange,提问作者Icode4food

