.NET6中MediatR多个Pipeline Behavior执行顺序及优先级设置方法
MediatR多管道行为执行顺序与优先级配置解答
一、当前注册方式的实际执行顺序
MediatR的IPipelineBehavior管道执行逻辑和ASP.NET Core中间件完全一致,采用嵌套式俄罗斯套娃模型,默认执行顺序完全由服务注册到DI容器的顺序决定:
- 你当前代码中四个管道的注册顺序为:
UnhandledExceptionBehaviour→AuthorizationBehaviour→ValidationBehaviour→PerformanceBehaviour - 请求流入阶段(调用
next()委托前的前置逻辑)严格按照注册顺序执行:先进入UnhandledExceptionBehaviour,再到AuthorizationBehaviour做权限校验,再到ValidationBehaviour做参数校验,再到PerformanceBehaviour,最后才会执行具体CommandHandler的业务逻辑 - 响应返回阶段(调用
next()委托后的后置逻辑)执行顺序完全反转:Handler执行完成后,先回到PerformanceBehaviour执行后置逻辑,再依次返回ValidationBehaviour、AuthorizationBehaviour,最后回到UnhandledExceptionBehaviour,结果才会返回给上游调用方
注意:你当前的注册顺序存在不符合常规范式的问题:
PerformanceBehaviour作为最后一个注册的管道,仅包裹了CommandHandler本身,统计到的耗时只会包含Handler的执行时间,不会覆盖授权、参数校验环节的耗时,如果需要统计全链路处理耗时,这个顺序需要调整。而UnhandledExceptionBehaviour放在第一个注册是正确的,作为最外层管道可以捕获后续所有管道和Handler抛出的异常。
二、管道行为执行优先级的设置方式
MediatR本身没有内置独立的优先级配置API,默认完全以DI注册顺序为执行依据,常用的优先级设置方案有两种:
方案1:直接调整注册顺序(最推荐,无额外侵入)
直接调整IPipelineBehavior<,>的注册代码先后位置即可,需要越先执行(越外层)的管道,放在越靠前的位置注册。
常规业务场景下的推荐注册顺序(从先到后)参考:
services.AddMediatR(Assembly.GetExecutingAssembly()); // 1. 全局异常处理管道(最外层,捕获所有内层管道、Handler抛出的异常) services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); // 2. 全链路监控/日志管道(包裹后续所有业务相关管道,统计全链路耗时、打印请求日志) services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); // 3. 授权校验管道 services.AddTransient(typeof(IPipelineBehavior<,>), typeof(AuthorizationBehaviour<,>)); // 4. 参数校验管道 services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); // 最后执行具体CommandHandler
方案2:自定义特性标记+自动排序(适合多模块自动注册场景)
如果你的项目存在分模块自动注册管道、不方便手动调整注册顺序的情况,可以通过自定义优先级特性+服务重排的方式统一控制顺序,实现步骤如下:
- 定义优先级标记特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class PipelineOrderAttribute : Attribute { /// <summary> /// 执行顺序,数值越小越先执行(越靠近管道外层) /// </summary> public int Order { get; } public PipelineOrderAttribute(int order) => Order = order; }
- 给自定义管道标记顺序值
[PipelineOrder(1)] public class UnhandledExceptionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { // 管道实现逻辑 } [PipelineOrder(2)] public class PerformanceBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { // 管道实现逻辑 } // 其他管道同理标记对应Order值即可
- 编写服务排序扩展方法,在所有管道注册完成后调用
public static class MediatRServiceExtensions { public static IServiceCollection SortMediatRPipelines(this IServiceCollection services) { // 查找所有IPipelineBehavior的服务注册 var pipelineRegistrations = services .Where(s => s.ServiceType.IsGenericType && s.ServiceType.GetGenericTypeDefinition() == typeof(IPipelineBehavior<,>)) .ToList(); // 移除原有注册 foreach (var reg in pipelineRegistrations) { services.Remove(reg); } // 按照Order值从小到大排序,未标记特性的管道默认排到最后 var sortedRegistrations = pipelineRegistrations.OrderBy(reg => { var implType = reg.ImplementationType; if (implType == null) return int.MaxValue; var orderAttr = implType.GetCustomAttribute<PipelineOrderAttribute>(); return orderAttr?.Order ?? int.MaxValue; }); // 按排序后的顺序重新注册 foreach (var reg in sortedRegistrations) { services.Add(reg); } return services; } }
- 在ConfigureServices中调用扩展方法
services.AddMediatR(Assembly.GetExecutingAssembly()); // 此处手动/自动注册管道时无需关心顺序 services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(AuthorizationBehaviour<,>)); // 最后调用排序方法,自动按照标记的优先级重排 services.SortMediatRPipelines();
内容的提问来源于stack exchange,提问作者Alireza Ahmadi
相关产品推荐
相关产品推荐

