如何为所有MediatR处理器添加全局异常日志记录?
如何为MediatR添加全局异常日志管道行为
问题背景
我尝试用IRequestExceptionAction记录MediatR处理器抛出的所有异常,不需要处理这些异常(它们可能已经被处理了)。我用的是Microsoft依赖注入,已经把RequestExceptionActionProcessorStrategy设置为ApplyForAllExceptions。
针对特定请求类型实现IRequestExceptionAction时,日志记录能正常工作;但想创建单个处理程序记录所有处理器的异常却失败了,我试过两种实现方式:
- 泛型处理程序
- 以
IRequest作为TRequest
请问该如何添加一个能触发所有MediatR处理器异常的管道行为?
解决方案
方法1:自定义泛型IRequestExceptionAction并手动注册
MediatR的自动扫描不会识别开放泛型的IRequestExceptionAction,需要手动注册这个泛型实现。
首先创建全局异常日志处理类:
public class GlobalRequestExceptionAction<TRequest, TException> : IRequestExceptionAction<TRequest, TException> where TRequest : notnull, IRequest where TException : Exception { private readonly ILogger<GlobalRequestExceptionAction<TRequest, TException>> _logger; public GlobalRequestExceptionAction(ILogger<GlobalRequestExceptionAction<TRequest, TException>> logger) { _logger = logger; } public Task Execute(TRequest request, TException exception, CancellationToken cancellationToken) { _logger.LogError(exception, "MediatR请求处理异常,请求类型:{RequestType}", typeof(TRequest).FullName); return Task.CompletedTask; } }
然后在依赖注入配置中注册该开放泛型类型:
services.AddMediatR(cfg => { cfg.RegisterServicesFromAssembly(typeof(Program).Assembly); cfg.RequestExceptionActionProcessorStrategy = RequestExceptionActionProcessorStrategy.ApplyForAllExceptions; // 注册全局泛型异常处理动作 cfg.AddOpenRequestExceptionAction(typeof(GlobalRequestExceptionAction<,>)); });
方法2:自定义管道行为(更灵活的替代方案)
如果IRequestExceptionAction的方式不符合预期,可以直接实现IPipelineBehavior来捕获所有经过管道的异常并记录,这种方式不受RequestExceptionActionProcessorStrategy设置的限制:
public class GlobalExceptionLoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull, IRequest<TResponse> { private readonly ILogger<GlobalExceptionLoggingBehavior<TRequest, TResponse>> _logger; public GlobalExceptionLoggingBehavior(ILogger<GlobalExceptionLoggingBehavior<TRequest, TResponse>> logger) { _logger = logger; } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { try { return await next(); } catch (Exception ex) { _logger.LogError(ex, "MediatR请求处理异常,请求类型:{RequestType}", typeof(TRequest).FullName); // 不处理异常,直接重新抛出,保留原有异常处理逻辑 throw; } } }
接着在依赖注入中注册这个管道行为:
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(GlobalExceptionLoggingBehavior<,>));
关键注意事项
- 使用
IRequestExceptionAction时,必须通过AddOpenRequestExceptionAction手动注册开放泛型,无法通过自动扫描识别 - 管道行为方式可以捕获所有流经MediatR管道的异常,不受
RequestExceptionActionProcessorStrategy的约束 - 两种方案都仅记录日志,不会拦截或处理异常,原有异常处理逻辑仍会生效
内容的提问来源于stack exchange,提问作者Craig Smitham
相关产品推荐
相关产品推荐

