通过ICarterModule构造注入ISender时,MediatR处理器无法解析作用域服务
MediatR处理器无法解析仓储:Carter模块构造注入IMediator vs 方法参数注入ISender的差异
问题原因
Carter的ICarterModule默认以单例生命周期注册,当你在模块构造函数中注入IMediator时,IMediator也会以单例实例存在。单例服务依赖根服务提供者解析依赖,若你的ISubscriptionRepository是注册为Scoped(仓储、DbContext类的常见生命周期),根容器无法正确解析绑定到请求上下文的Scoped服务,就会出现依赖解析失败的错误。
而在端点方法中注入ISender时,ISender是从当前请求的Scoped服务提供者中获取的,能匹配Scoped依赖的生命周期,因此可以正常解析ISubscriptionRepository。
解决方案
方案1:推荐——在端点方法中直接注入ISender
这是最符合Minimal API和Carter设计风格的方式,完全规避生命周期不匹配问题:
public class SubscriptionModule : ICarterModule { public void AddRoutes(IEndpointRouteBuilder app) { app.MapPost("/subscriptions", async (CreateSubscriptionCommand command, ISender sender) => { var result = await sender.Send(command); return Results.Ok(result); }) .WithName("CreateSubscription") .Produces<SubscriptionDto>(StatusCodes.Status200OK); } }
方案2:通过IServiceProvider创建Scoped上下文(特殊场景用)
如果必须在模块构造函数中持有服务引用,可注入IServiceProvider,在请求时创建Scoped范围来获取ISender:
public class SubscriptionModule : ICarterModule { private readonly IServiceProvider _serviceProvider; public SubscriptionModule(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public void AddRoutes(IEndpointRouteBuilder app) { app.MapPost("/subscriptions", async (CreateSubscriptionCommand command) => { // 创建Scoped范围,确保依赖解析在请求上下文内 using var scope = _serviceProvider.CreateScope(); var sender = scope.ServiceProvider.GetRequiredService<ISender>(); var result = await sender.Send(command); return Results.Ok(result); }); } }
方案3:调整仓储生命周期为Singleton(不推荐)
如果你的仓储不依赖Scoped服务(如无DbContext依赖),可以将ISubscriptionRepository注册为Singleton,但这不符合大多数整洁架构中仓储的设计原则,可能引发并发问题,仅作为临时 workaround:
// Infrastructure层注册代码 services.AddSingleton<ISubscriptionRepository, SubscriptionRepository>();
验证DI注册正确性
确保你的MediatR和仓储注册逻辑无误:
- Application层注册MediatR:
public static IServiceCollection AddApplication(this IServiceCollection services) { // 注册当前程序集中的所有MediatR处理器 services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(CreateSubscriptionCommand).Assembly)); return services; }
- Infrastructure层注册仓储:
public static IServiceCollection AddInfrastructure(this IServiceCollection services) { // 通常注册为Scoped services.AddScoped<ISubscriptionRepository, SubscriptionRepository>(); // 其他基础设施服务注册(如DbContext) return services; }
内容的提问来源于stack exchange,提问作者CarlosIS
相关产品推荐
相关产品推荐

