MediatR多DI容器集成指南:Autofac、DryIoc、Lamar等7大容器接入清单
【免费下载链接】MediatRSimple, unambitious mediator implementation in .NET项目地址: https://gitcode.com/gh_mirrors/me/MediatR
MediatR是 .NET 中一款简洁、无依赖的中介者(Mediator)实现,支持请求/响应、命令、查询、通知与流式请求。而"MediatR 如何接入 Autofac、DryIoc、Lamar 等第三方依赖注入(DI)容器"是不少新手上手的第一个坎——官方内置的AddMediatR只对 Microsoft DI 生效。本文给出一份7 大容器接入清单:每种容器要注册哪些类型、流水线(Pipeline)行为如何挂载、有哪些容易踩的坑,全部对照仓库内可运行的官方示例讲解。
想跟着动手的话,先克隆仓库:
git clone https://gitcode.com/gh_mirrors/me/MediatR所有示例都在 samples/ 目录下,用MediatR.slnx打开即可逐个运行验证。
一、为什么第三方容器需要"手动接入"?
MediatR 的核心只依赖一个IServiceProvider。它在任何容器里要正常工作,只需要满足 4 件事:
- 能解析出
IMediator(内部实现 Mediator.cs) - 能解析出
IEnumerable<IRequestHandler<TRequest, TResponse>>等处理器集合 - 能解析出
IEnumerable<IPipelineBehavior<TRequest, TResponse>>等流水线行为 - 处理器按**瞬态(Transient)**生命周期注册
Microsoft 容器通过AddMediatR自动完成了以上全部(见 MediatRServiceCollectionExtensions.cs),而其他容器要么有"Microsoft DI 适配器"可借用,要么就得手动扫描注册。下文按接入难度从低到高排序。
二、7 大容器接入速查清单
| 容器 | 接入方式 | 是否借助 MS DI 适配器 | 官方示例 |
|---|---|---|---|
| Stashbox | 一行RegisterAssemblies | 否 | Program.cs |
| DryIoc | WithDependencyInjectionAdapter | ✅ 是 | Program.cs |
| LightInject | 按接口过滤扫描 +RegisterOrdered | ✅ 是 | Program.cs |
| SimpleInjector | RegisterAssemblyTypes+ 集合注册 | 部分 | Program.cs |
| Autofac | AsClosedTypesOf扫描 5 种开泛型 | ✅ 是 | Program.cs |
| Lamar | ConnectImplementationsToTypesClosing扫描 | 否 | Program.cs |
| Castle.Windsor | BasedOn扫描 +CollectionResolver | 否 | Program.cs |
下面逐个拆解关键代码。
三、内置基线:Microsoft DI 的一行AddMediatR
这是理解其他容器的基线。在 README.md 中可以看到,只需一行:
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Startup>());它会从指定程序集扫描并注册:IMediator、ISender、IPublisher,以及IRequestHandler<,>、INotificationHandler<>、IStreamRequestHandler<>、IRequestExceptionHandler<,,>、IRequestExceptionAction<,>的全部实现,生命周期均为 transient。注意:流水线行为不会被自动扫描,需要用cfg.AddBehavior<>()等方法显式添加。
四、Stashbox 接入:代码最少的容器
Stashbox 内置了 MediatR 感知的程序集扫描规则,是整个 samples/MediatR.Examples.Stashbox/ 里代码最短的:
var container = new StashboxContainer() .RegisterAssemblies(new[] { typeof(Mediator).Assembly, typeof(Ping).Assembly }, serviceTypeSelector: Rules.ServiceRegistrationFilters.Interfaces); return container.GetRequiredService<IMediator>();serviceTypeSelector: Rules.ServiceRegistrationFilters.Interfaces这一参数是关键——它会按接口注册实现类型,处理器集合和流水线行为都能被正确解析。
五、DryIoc 接入:借助 DI 适配器一行注册
DryIoc 官方提供 DryIoc.Microsoft.DependencyInjection 适配器,示例见 samples/MediatR.Examples.DryIoc/Program.cs:
container.RegisterMany(new[] { typeof(IMediator).GetAssembly(), typeof(Ping).GetAssembly() }, Registrator.Interfaces); var adapterContainer = container.WithDependencyInjectionAdapter(services); return adapterContainer.GetRequiredService<IMediator>();⚠️一个专属坑点:Mediator有多个构造函数,DryIoc 默认可能选不中你想要的那个。示例代码中给出了两种处理方式:要么加规则rules.With(FactoryMethod.ConstructorWithResolvableArguments),要么像示例那样显式指定构造函数参数(Made.Of(() => new Mediator(Arg.Of<IServiceProvider>())))。
六、LightInject 接入:接口过滤扫描 + 有序注册流水线
LightInject 的示例(samples/MediatR.Examples.LightInject/Program.cs)分三步:
- 扫描处理器:
RegisterAssembly时用过滤函数,只注册实现了IRequestHandler<,>或INotificationHandler<>的类型; - 注册流水线:用
RegisterOrdered(typeof(IPipelineBehavior<,>), new[] { ... })显式声明行为的执行顺序(注意:MediatR 中后注册的行为先执行); - 取适配器:
serviceContainer.CreateServiceProvider(services)得到IServiceProvider再解析IMediator。
七、SimpleInjector 接入:注意开泛型处理器的特殊注册
SimpleInjector 示例(samples/MediatR.Examples.SimpleInjector/Program.cs)有两处值得注意:
- 用
container.Register(typeof(IRequestHandler<,>), assemblies)这类"按开泛型 + 程序集"的 API 扫描处理器; - 开泛型处理器必须显式纳入:默认的
GetTypesToRegister不会注册开泛型定义(如ConstrainedPingedHandler<>),示例中通过IncludeGenericTypeDefinitions = true补齐,否则带泛型约束的处理器会"失踪"; - 流水线用
container.Collection.Register注册为集合。
八、Autofac 接入:AsClosedTypesOf 扫描 5 种处理器
Autofac 是最常被问到的容器,示例在 samples/MediatR.Examples.Autofac/Program.cs。核心套路:
- 定义 5 种 MediatR 开泛型接口数组(
IRequestHandler<,>、IRequestExceptionHandler<,,>、IRequestExceptionAction<,>、INotificationHandler<>、IStreamRequestHandler<,>); - 对每种接口用
RegisterAssemblyTypes(...).AsClosedTypesOf(mediatrOpenType).AsImplementedInterfaces()扫描; - 用
builder.Populate(services)桥接 Microsoft DI,再用AutofacServiceProvider解析IMediator。
示例代码里有两条实战提示值得留意:Autofac 返回最后注册的类型在前(影响流水线顺序),以及"一个类同时实现多种处理器接口会导致被调用两次"。
九、Lamar 接入:ConnectImplementationsToTypesClosing 自动接线
Lamar 的扫描 API 表达力很强,示例(samples/MediatR.Examples.Lamar/Program.cs)在一个cfg.Scan块里完成:
scanner.AssemblyContainingType<Ping>(); scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>)); scanner.ConnectImplementationsToTypesClosing(typeof(INotificationHandler<>)); // ... 以及另外两种异常处理器接口随后用cfg.For(typeof(IPipelineBehavior<,>)).Add(...)逐条挂接异常处理、前后置处理器等流水线行为,并显式声明cfg.For<IMediator>().Use<Mediator>().Transient()。整体配置风格直观,适合团队中已有 .NET 经验的新手阅读。
十、Castle.Windsor 接入:CollectionResolver 与逆变过滤
Windsor 是清单中"机关"最多的容器(samples/MediatR.Examples.Windsor/Program.cs),三件必备的事:
CollectionResolver子解析器:MediatR 依赖IEnumerable<T>集合解析,Windsor 默认不支持,必须AddSubResolver(new CollectionResolver(kernel));ContravariantFilter:见 ContravariantFilter.cs,用于让 MediatR 依赖的 C# 泛型逆变(如用IRequestHandler<IRequest, Unit>兼容更具体的请求)在 Windsor 里也能生效;- 处理器扫描:
BasedOn(typeof(IRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches(),注意AllowMultipleMatches()不能漏。
另外记得:Windsor 默认生命周期是Singleton,示例注释中特别提醒在 Web 场景下应改用PerWebRequest或 Transient 风格,避免IMediator被单例化带来的隐式共享状态问题。
十一、通用避坑清单:接入任何容器都检查一遍
- ✅5 种处理器接口:
IRequestHandler<,>、INotificationHandler<>、IStreamRequestHandler<,>、IRequestExceptionHandler<,,>、IRequestExceptionAction<,>是否全部扫描注册?漏掉异常处理器,RequestExceptionHandler相关功能会静默失效; - ✅集合解析:容器是否支持
IEnumerable<T>多实现解析(Windsor 需子解析器,SimpleInjector 用集合注册); - ✅流水线顺序:MediatR 中后注册的行为先执行,用"顺序注册"API(如 LightInject 的
RegisterOrdered)时方向别搞反; - ✅生命周期:
IMediator与各处理器建议 transient(Lamar 示例中注释:"最多 container scoped"); - ✅开泛型处理器:带泛型约束的处理器(开泛型定义)需要显式纳入注册(SimpleInjector 需
IncludeGenericTypeDefinitions); - ✅构造选择:
Mediator有多个构造函数,非 Microsoft 容器建议显式指定(DryIoc 示例的做法)。
十二、怎么验证自己接对了?
每个容器示例都复用了同一个功能覆盖最全的运行器 Runner.cs(Autofac、Windsor、Stashbox 还开启了流式请求测试),它会实际发出 Ping/Pong 请求、通知、异常与流式请求,逐一检验处理器与流水线是否都按预期触发——你只需运行对应示例项目并对照控制台输出。
如果想看同一套"容器装配是否合规"的自动化断言,可以研究 test/MediatR.DependencyInjectionTests/ 目录:其中 BaseServiceProviderFixture.cs 定义了对 6 种容器统一的解析检查项(公共/私有/内部处理器能否被正确解析等),各容器只需实现一个 fixture 即可复用整套断言。
十三、选型小结
- 新项目和 .NET 全家桶:直接用 Microsoft DI +
AddMediatR,零额外代码; - 想用轻量容器:Stashbox 和 DryIoc 接入成本最低(几行代码 + 适配器);
- 已有 Autofac/Lamar 存量项目:按本文的"开泛型扫描 + 集合注册"套路补一段注册代码即可,官方示例可整段参照;
- 维护 Windsor 老系统:重点检查
CollectionResolver与ContravariantFilter是否都已就位。
掌握"5 种处理器接口 + 流水线集合 + 生命周期"这个核心心智模型后,你会发现无论换成哪个容器,MediatR 的接入都只是换个 API 表达同一件事。
【免费下载链接】MediatRSimple, unambitious mediator implementation in .NET项目地址: https://gitcode.com/gh_mirrors/me/MediatR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考