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

如何用ResultFilterAttribute封装ResponseBase替代ControllerBase的Result方法

实现方案

1. 先确认ResponseBase<T>结构(示例)

假设你已有的响应封装类结构如下(可根据实际调整):

public class ResponseBase<T>
{
    public int Code { get; set; }
    public string Message { get; set; }
    public T Data { get; set; }

    public ResponseBase(int code, string message, T data)
    {
        Code = code;
        Message = message;
        Data = data;
    }
}

// 封装静态快捷方法,简化调用
public static class ResponseBase
{
    public static ResponseBase<T> Success<T>(T data) => new(200, "操作成功", data);
    public static ResponseBase<T> Fail<T>(string message, int code = 500) => new(code, message, default);
}

2. 实现自定义ResultFilterAttribute

继承ASP.NET Core的ResultFilterAttribute,重写异步处理方法,自动封装响应:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

public class WrapResultFilterAttribute : ResultFilterAttribute
{
    public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        // 跳过已封装为ResponseBase的结果,避免重复处理
        if (context.Result is ObjectResult objResult)
        {
            if (objResult.Value is ResponseBase<object> || objResult.Value?.GetType().IsGenericType == true 
                && objResult.Value.GetType().GetGenericTypeDefinition() == typeof(ResponseBase<>))
            {
                await next();
                return;
            }

            // 封装正常返回数据
            var wrappedResult = ResponseBase.Success(objResult.Value);
            context.Result = new OkObjectResult(wrappedResult);
        }
        // 处理错误状态码的响应(可选,按需添加)
        else if (context.Result is StatusCodeResult statusCodeResult)
        {
            var errorMsg = statusCodeResult.StatusCode switch
            {
                400 => "请求参数无效",
                401 => "未授权访问",
                404 => "请求资源不存在",
                _ => "请求处理失败"
            };
            var wrappedError = ResponseBase.Fail<object>(errorMsg, statusCodeResult.StatusCode);
            context.Result = new ObjectResult(wrappedError) { StatusCode = statusCodeResult.StatusCode };
        }

        await next();
    }
}

3. 注册过滤器

有两种注册方式,按需选择:

全局注册(所有接口自动生效)

在Program.cs中配置全局过滤器:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    // 添加全局结果过滤器
    options.Filters.Add<WrapResultFilterAttribute>();
});

var app = builder.Build();

// 其他中间件配置...

app.MapControllers();
app.Run();

局部注册(仅指定Controller/Action生效)

在目标控制器或Action上添加特性标记:

[WrapResultFilter]
public class ConfigurationController : ControllerBase
{
    // 直接返回原始数据,会被自动封装为ResponseBase
    [HttpGet("list")]
    public IEnumerable<string> GetConfigs()
    {
        return new List<string> { "ConfigA", "ConfigB" };
    }

    // 手动返回自定义响应时,过滤器会跳过封装
    [HttpGet("error")]
    public ResponseBase<string> GetError()
    {
        return ResponseBase.Fail<string>("获取配置失败,请稍后重试");
    }
}

4. 简化BaseApiController(可选)

原来的BaseApiController中的Result<T>方法可以保留(兼容旧代码),也可以直接移除,因为过滤器会自动完成封装:

public class BaseApiController : ControllerBase
{
    // 可选:保留该方法,供需要手动封装的场景使用
    protected IActionResult Result<T>(T data)
    {
        return Ok(ResponseBase.Success(data));
    }
}

内容的提问来源于stack exchange,提问作者Matt Ghafouri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 09:54:19