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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:10:30