泛型IPublisherService依赖注入报错:无法找到合适构造函数
泛型依赖注入失败问题解决
问题场景
使用未绑定泛型进行依赖注入时,注入服务失败,相关代码及错误信息如下:
接口定义
public interface IPublisherService<TEntity> where TEntity : class { Task<TEntity> PublishAsync(TEntity entity, CancellationToken cancellationToken); }
服务实现
public class PublisherService<TEntity> : IPublisherService<TEntity> where TEntity : class { private readonly ILogger _logger; private readonly IPublishEndpoint _publishEndpoint; protected PublisherService(ILogger<PublisherService<TEntity>> logger, IPublishEndpoint publishEndpoint) { this._logger = logger ?? throw new ArgumentNullException(nameof(logger)); this._publishEndpoint = publishEndpoint ?? throw new ArgumentNullException(nameof(publishEndpoint)); } public async Task<TEntity> PublishAsync(TEntity entity, CancellationToken cancellationToken) { try { await _publishEndpoint.Publish(entity, cancellationToken); } catch (Exception ex) { _logger.LogInformation($"Could not send message to queue Reason: {ex.Message}"); } return entity; } }
服务注册
public static class ServiceCollectionExtension { public static IServiceCollection RegisterPublishers(this IServiceCollection services) => services .AddScoped(typeof(IPublisherService<>), typeof(PublisherService<>)); } // 注册调用 builder.Services.RegisterPublishers();
错误提示
System.InvalidOperationException: A suitable constructor for type 'Marel.Livestock.MassTransit.Publisher.Services.Generics.PublisherService`1[Marel.Livestock.Models.TestClass.TheTestClass]' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.
错误调用栈:
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot, Boolean throwOnConstraintViolation) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType) at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) at lambda_method10(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass7_0.<CreateActivator>b__0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass6_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
问题原因
.NET依赖注入容器仅能访问类的public构造函数来实例化对象,当前PublisherService<TEntity>的构造函数使用protected修饰,容器无法调用该构造函数创建服务实例,因此抛出无法找到合适构造函数的错误。
解决步骤
将PublisherService<TEntity>的构造函数访问修饰符改为public即可:
public class PublisherService<TEntity> : IPublisherService<TEntity> where TEntity : class { private readonly ILogger _logger; private readonly IPublishEndpoint _publishEndpoint; // 修改为public构造函数 public PublisherService(ILogger<PublisherService<TEntity>> logger, IPublishEndpoint publishEndpoint) { this._logger = logger ?? throw new ArgumentNullException(nameof(logger)); this._publishEndpoint = publishEndpoint ?? throw new ArgumentNullException(nameof(publishEndpoint)); } // 其余代码保持不变 }
额外说明
若需保留构造函数的protected修饰(例如用于子类继承),可通过以下方式处理:
- 为子类添加public构造函数
- 使用工厂模式手动创建服务实例并注册到DI容器中
但对于当前场景,直接将构造函数改为public是最简单有效的解决方案。
内容的提问来源于stack exchange,提问作者CorrieJanse
相关产品推荐
相关产品推荐

