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

Wolverine中间件直接返回结果的优雅实现方案咨询(从MediatR迁移场景)

Wolverine中间件直接返回结果的优雅实现方案咨询(从MediatR迁移场景)

兄弟,我太懂你从MediatR转Wolverine的适配痛点了——MediatR里Behavior直接返回结果的操作顺手得不行,换到Wolverine突然卡壳确实闹心😅。你说的这个“中间件直接返回结果、不用每个Handler都做判断”的需求完全合理,我之前踩过类似的坑,给你分享两个亲测有效的优雅方案:

方案一:泛型中间件(类型安全,针对特定消息/返回类型)

这个方案适合你有明确消息类型(比如InputDto)和返回类型(比如OutputDto)的场景,完全类型安全,代码也清爽:

1. 编写泛型授权中间件

public class AuthorizationMiddleware<TInput, TOutput>
    where TOutput : new()
{
    public async Task<(HandlerContinuation, TOutput)> BeforeAsync(TInput input)
    {
        // 这里替换成你的实际授权逻辑
        if (!IsUserAuthorized(input))
        {
            // 授权失败时,直接返回终止信号+错误结果
            return (HandlerContinuation.Stop, new TOutput { Valid = false });
        }

        // 授权通过,继续执行Handler
        return (HandlerContinuation.Continue, default);
    }

    private bool IsUserAuthorized(TInput input)
    {
        // 示例:模拟授权失败
        return false;
    }
}

2. 精准绑定中间件到目标消息

注册时明确指定这个中间件只作用于InputDto类型的消息,避免全局冗余:

builder.UseWolverine(options =>
{
    options.Policies
        .ForMessagesOfType<InputDto>()
        .AddMiddleware<AuthorizationMiddleware<InputDto, OutputDto>>();
});

3. 控制器调用(无需修改原有代码)

你的原有Controller代码完全不用改,现在InvokeAsync会直接拿到中间件返回的OutputDto,不会再出现null的情况:

[HttpGet(Name = "GetWeatherForecast")]
public async Task<OutputDto> Get()
{
    var result = await _bus.InvokeAsync<OutputDto>(new InputDto { Id = 5 });
    return result; // 现在能正确拿到Valid=false的结果
}

方案二:全局通用中间件(适配所有统一格式的返回结果)

如果你的系统里有很多类似的返回Dto(都带Valid属性),不想为每个消息写单独的泛型中间件,可以用这个更灵活的方案:

1. 编写全局授权中间件

利用Wolverine的IMessageContext来设置结果,反射处理通用返回类型:

public class GlobalAuthorizationMiddleware
{
    public async Task<HandlerContinuation> BeforeAsync(IMessageContext context, object input)
    {
        // 这里替换成你的全局授权逻辑
        if (!IsAuthorized(input))
        {
            // 获取当前消息对应的Handler返回类型
            var returnType = context.Message.Type.GetHandlerReturnType();
            // 创建返回结果实例
            var result = Activator.CreateInstance(returnType);
            // 设置Valid属性(假设所有返回Dto都有这个属性)
            returnType.GetProperty("Valid")?.SetValue(result, false);
            
            // 将结果绑定到Context,终止管道
            context.SetResult(result);
            return HandlerContinuation.Stop;
        }

        return HandlerContinuation.Continue;
    }

    private bool IsAuthorized(object input)
    {
        // 通用授权判断逻辑
        return false;
    }
}

// 扩展方法:获取Handler的返回类型
public static Type GetHandlerReturnType(this Type messageType)
{
    // 示例简化逻辑:假设Handler命名为[MessageType]Handler,返回Task<T>
    var handlerType = Assembly.GetExecutingAssembly().GetTypes()
        .First(t => t.Name == $"{messageType.Name}Handler");
    
    var handleMethod = handlerType.GetMethod("Handle");
    var taskReturnType = handleMethod.ReturnType.GenericTypeArguments[0];
    return taskReturnType;
}

2. 全局注册中间件

builder.UseWolverine(options =>
{
    options.Policies.AddMiddleware<GlobalAuthorizationMiddleware>();
});

为什么你之前的代码会返回null?

你之前的中间件写法其实方向是对的,但问题出在中间件和消息/返回类型的绑定不明确——Wolverine无法自动推断非泛型中间件返回的OutputDto应该作为最终结果,用泛型中间件明确指定输入输出类型后,结果就能正确传递了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 03:10:16