You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何封装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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 11:31:15