如何封装MediatR返回类型并使IPipelineBehavior生效?
问题:MediatR封装返回类型后IPipelineBehavior无法执行
我希望所有请求处理器都返回IDispatchResult<TResponse>,以此为TResponse提供成功状态、验证错误列表等额外上下文信息,但修改代码后,自定义的IPipelineBehavior(即MyValidator)不再执行。
以下是可正常运行的标准代码:
internal class Program { static async Task Main(string[] args) { var services = new ServiceCollection(); services.AddMediatR(x => x .RegisterServicesFromAssemblyContaining<Program>() .AddBehavior(typeof(IPipelineBehavior<,>), typeof(MyValidator<,>), ServiceLifetime.Scoped)); IServiceProvider serviceProvider = services.BuildServiceProvider().CreateScope().ServiceProvider; IMediator mediator = serviceProvider.GetRequiredService<IMediator>(); MyResponse response = await mediator.Send(new MyCommand()); } } public class MyValidator<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> { public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { Console.WriteLine("Middleware executed."); return next(); } } public class MyCommand : IRequest<MyResponse> { } public class MyResponse { } public class MyCommandHandler : IRequestHandler<MyCommand, MyResponse> { public Task<MyResponse> Handle(MyCommand request, CancellationToken cancellationToken) { Console.WriteLine("Handler executed."); throw new NotImplementedException(); } }
修改为封装返回类型后,中间件无法执行,代码如下:
internal class Program { static async Task Main(string[] args) { var services = new ServiceCollection(); services.AddScoped<IDispatcher, Dispatcher>(); services.AddMediatR(x => x .RegisterServicesFromAssemblyContaining<Program>() .AddBehavior(typeof(IPipelineBehavior<,>), typeof(MyValidator<,>), ServiceLifetime.Scoped)); IServiceProvider serviceProvider = services.BuildServiceProvider().CreateScope().ServiceProvider; var dispatcher = serviceProvider.GetRequiredService<IDispatcher>(); IDispatchResult<MyResponse> response = await dispatcher.Send<MyCommand, MyResponse>(new MyCommand()); Console.WriteLine(response is IDispatchResult<object>); Console.ReadLine(); } } public class MyValidator<TRequest, TResponse> : IPipelineBehavior<TRequest, IDispatchResult<TResponse>> where TRequest : IRequest<IDispatchResult<TResponse>> where TResponse : class { public Task<IDispatchResult<TResponse>> Handle(TRequest request, RequestHandlerDelegate<IDispatchResult<TResponse>> next, CancellationToken cancellationToken) { Console.WriteLine("Middleware executed"); return next(); } } public class MyCommand : IRequest<IDispatchResult<MyResponse>> { } public class MyResponse { } public class MyCommandHandler : IRequestHandler<MyCommand, IDispatchResult<MyResponse>> { public async Task<IDispatchResult<MyResponse>> Handle(MyCommand request, CancellationToken cancellationToken) { await Task.Yield(); Console.WriteLine("Handler executed"); return new DispatchOKResult<MyResponse>(new MyResponse()); } } public interface IDispatchResult<out TPayload> where TPayload: class { public TPayload? Payload { get; } } public class DispatchOKResult<TPayload> : IDispatchResult<TPayload> where TPayload: class { public TPayload? Payload { get; set; } public DispatchOKResult(TPayload? payload) { Payload = payload; } } public interface IDispatcher { Task<IDispatchResult<TResponse>> Send<TRequest, TResponse>(TRequest request) where TRequest : IRequest<IDispatchResult<TResponse>> where TResponse : class; } public class Dispatcher : IDispatcher { private readonly IMediator Mediator; public Dispatcher(IMediator mediator) { Mediator = mediator; } public Task<IDispatchResult<TResponse>> Send<TRequest, TResponse>(TRequest request) where TRequest : IRequest<IDispatchResult<TResponse>> where TResponse: class => Mediator.Send(request); }
解决方案
问题核心是泛型约束与MediatR行为注册的匹配逻辑不兼容,可通过以下两种方式修复:
方式一:调整行为泛型定义,兼容开放泛型匹配
修改MyValidator的泛型约束,让它能被MediatR的开放泛型注册逻辑识别:
public class MyValidator<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> where TResponse : IDispatchResult<object> { public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { Console.WriteLine("Middleware executed"); return next(); } }
这种方式下,原注册代码AddBehavior(typeof(IPipelineBehavior<,>), typeof(MyValidator<,>))可以正常匹配所有返回IDispatchResult<>类型的请求。
方式二:明确指定行为的泛型匹配类型
如果要保留原MyValidator的泛型定义,需要在注册时明确指定泛型参数的匹配形式:
services.AddMediatR(x => x .RegisterServicesFromAssemblyContaining<Program>() .AddBehavior(typeof(IPipelineBehavior<, IDispatchResult<>>), typeof(MyValidator<,>), ServiceLifetime.Scoped));
注意:这种方式在部分MediatR版本中可能存在匹配稳定性问题,优先推荐第一种方案。
内容的提问来源于stack exchange,提问作者Peter Morris
相关产品推荐
相关产品推荐

