如何让ASP.NET Core 5 Web API所有控制器统一返回Result对象?
ASP.NET Core 5 Web API 统一返回结果封装实现
1. 定义统一Result模型
首先创建封装返回结果的模型类,包含需求中的所有字段,同时提供静态方法快速构建成功/失败结果:
// 泛型版本,用于带具体返回值的场景 public class Result<T> { public bool IsSuccess { get; set; } public T Value { get; set; } public object Error { get; set; } public int? TotalCount { get; set; } public static Result<T> Success(T value, int? totalCount = null) { return new Result<T> { IsSuccess = true, Value = value, TotalCount = totalCount }; } public static Result<T> Failure(object error) { return new Result<T> { IsSuccess = false, Error = error }; } } // 非泛型版本,用于无具体返回值的场景 public class Result : Result<object> { public new static Result Success(object value = null, int? totalCount = null) { return new Result { IsSuccess = true, Value = value, TotalCount = totalCount }; } public new static Result Failure(object error) { return new Result { IsSuccess = false, Error = error }; } }
2. 实现全局结果包装过滤器
创建IAsyncResultFilter实现类,拦截所有控制器的返回结果,自动封装为Result对象:
public class ResultWrapperFilter : IAsyncResultFilter { public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { // 处理ObjectResult类型的返回(包括直接返回实体、ActionResult<T>等) if (context.Result is ObjectResult objectResult) { var wrappedResult = objectResult.Value switch { null => Result.Success(null), IEnumerable enumerable => Result.Success(enumerable, enumerable.Cast<object>().Count()), _ => Result.Success(objectResult.Value) }; // 替换原结果为封装后的Result context.Result = new ObjectResult(wrappedResult) { StatusCode = objectResult.StatusCode }; } // 处理StatusCodeResult类型的返回(如NotFound、NoContent等) else if (context.Result is StatusCodeResult statusCodeResult) { var wrappedResult = statusCodeResult.StatusCode is >= 200 and < 300 ? Result.Success(null) : Result.Failure(new { Message = "请求失败", StatusCode = statusCodeResult.StatusCode }); context.Result = new ObjectResult(wrappedResult) { StatusCode = statusCodeResult.StatusCode }; } await next(); } }
3. 实现全局异常捕获过滤器
创建IAsyncExceptionFilter实现类,捕获未处理的异常,封装为错误Result:
public class GlobalExceptionFilter : IAsyncExceptionFilter { private readonly ILogger<GlobalExceptionFilter> _logger; public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger) { _logger = logger; } public async Task OnExceptionAsync(ExceptionContext context) { _logger.LogError(context.Exception, "发生未处理异常"); var errorInfo = new { Message = "服务器发生意外错误", Detail = context.Exception.Message }; context.Result = new ObjectResult(Result.Failure(errorInfo)) { StatusCode = StatusCodes.Status500InternalServerError }; context.ExceptionHandled = true; await Task.CompletedTask; } }
4. 注册全局过滤器
在Startup.cs的ConfigureServices方法中注册上述两个过滤器,让所有控制器生效:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { options.Filters.Add<ResultWrapperFilter>(); options.Filters.Add<GlobalExceptionFilter>(); }); }
5. 控制器使用示例
控制器无需手动返回Result对象,直接返回原有类型即可,过滤器会自动封装:
[ApiController] [Route("api/users")] public class UsersController : ControllerBase { [HttpGet] public IEnumerable<User> GetAll() { // 返回列表,自动封装为带TotalCount的Result return new List<User> { new User { Id = 1, Name = "张三" }, new User { Id = 2, Name = "李四" } }; } [HttpGet("{id}")] public ActionResult<User> GetById(int id) { if (id <= 0) { // NotFound会被封装为IsSuccess:false的Result return NotFound(); } return new User { Id = id, Name = "测试用户" }; } [HttpPost] public IActionResult Create(User user) { // CreatedAtAction的结果会被自动封装 return CreatedAtAction(nameof(GetById), new { id = user.Id }, user); } }
效果说明
- 成功返回列表时,响应格式:
{ "isSuccess": true, "value": [{"id":1,"name":"张三"},{"id":2,"name":"李四"}], "error": null, "totalCount": 2 }
- 错误返回(如NotFound)时,响应格式:
{ "isSuccess": false, "value": null, "error": {"message":"请求失败","statusCode":404}, "totalCount": null }
- 异常返回时,响应格式:
{ "isSuccess": false, "value": null, "error": {"message":"服务器发生意外错误","detail":"具体异常信息"}, "totalCount": null }
内容的提问来源于stack exchange,提问作者Hani Draidi
相关产品推荐
相关产品推荐

