MediatR本质是进程内请求路由工具,非经典中介者模式实现;new MediatR()报错因它不维护同事实例引用,只认注册的IRequestHandler,无法支撑UI联动等持续协作场景。

MediatR 不是“中介者模式的高级实现”,它本质是进程内请求路由工具;真要落地经典中介者模式(如 UI 控件联动、游戏对象协作),必须手写 IMediator + 同事类双向引用,否则会掉进状态不可控、循环调用、内存泄漏三重坑。
为什么 new MediatR() 会报 Handler was not found for request
这不是配置漏了,而是你误把 MediatR 当成了通用中介者容器。它只认注册过的 IRequestHandler<TRequest, TResponse>,且不维护任何同事实例引用——它根本不知道谁在发消息、谁该被通知。
- 错误典型:在窗体里
new Mediator()然后传给TextBox和Button,指望它们能互相感知状态 → 实际上MediatR无状态、无生命周期管理,Send()调用完就丢,无法支撑持续协作 - 真正该注册的是你自己的
ConcreteMediator类,比如services.AddSingleton<IChatMediator, ChatRoomMediator>(),而不是靠MediatR自动发现 - 若坚持用
MediatR,必须把“状态判断逻辑”全搬到 handler 里写死,比如if (user.IsOnline) NotifyOthers(),但这已脱离中介者模式本意,变成一堆 if-else 的消息分发器
MediatR 初始化失败:AddMediatR 找不到扩展方法或 Handler 未注册
不是包没装,而是 v12+ 移除了无参重载。调用 AddMediatR() 报错“未找到该扩展方法”,大概率是因为只装了 MediatR 主包,漏了 MediatR.Extensions.Microsoft.DependencyInjection;即使装对了,空参数调用也会编译失败。
- 必须用泛型重载:
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly)); - 若 Handler 分散在多个程序集(如
Application、Infrastructure),需显式列出:RegisterServicesFromAssemblies(typeof(CreateUserCommand).Assembly, typeof(EmailNotificationHandler).Assembly) - 漏掉任一程序集 → 运行时抛
InvalidOperationException: Handler was not found for request,且堆栈不提示缺哪个程序集,只能靠日志或断点查cfg.ServiceClosures
IRequest<TResponse> 和 IRequest 怎么选才不编译失败也不语义错乱
关键不在“有没有返回值”,而在“调用方是否需要同步等待并消费结果”。写成 IRequest<void> 会编译失败,这不是疏忽,是类型系统在拦你。
-
IRequest<Guid>、IRequest<UserDto>:适合查询或需返回业务标识的命令(如新建资源 ID) - 想表示“执行成功但无业务数据”,用
IRequest<Unit>(MediatR自带的不可变占位类型) -
IRequest(无泛型):等价于IRequest<Unit>,语义更清晰,推荐用于纯副作用操作(如发短信、触发 webhook) - 错误示范:
public record CreateUserCommand() : IRequest<void>→ 编译报错;正确写法是IRequest<Guid>或IRequest
Send vs Publish:命令和事件混用会导致什么后果
Send 是请求-响应模型,Publish 是事件广播模型。强行用 Send 发领域事件,或用 Publish 调用命令处理逻辑,会导致行为不可控甚至死锁。
-
Send<TResponse>():严格一对一,只找一个IRequestHandler<TRequest, TResponse>,等待其完成并返回结果;适用于 CQRS 中的 Command 和 Query -
Publish():一对多,所有INotificationHandler<TNotification>都会被调用,且不等待全部完成(默认并行,可配置顺序) - 典型误用:用
Publish(new CreateUserCommand())替代Send→ 命令被当成事件广播,可能触发多个 handler,破坏事务边界与幂等性 - 高并发下尤其危险:
Publish中某个 handler 耗时(如调第三方 API),会阻塞后续通知,甚至压垮线程池
最常被忽略的一点是:MediatR 的 IMediator 必须注册为 Scoped 生命周期,手动写 AddSingleton<IMediator> 或漏掉 DI 容器作用域配置,会导致运行时解析失败——而这个错误往往在深层调用链中才暴露,排查成本远高于初始化时多敲一行 .AddScoped<IMediator, Mediator>()。


















