如何用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
相关产品推荐
相关产品推荐

