Microsoft.AspNetCore.Http.IContentTypeHttpResult Microsoft.AspNetCore.Http.IFileHttpResult Microsoft.AspNetCore.Http.INestedHttpResult Microsoft.AspNetCore.Http.IStatusCodeHttpResult Microsoft.AspNetCore.Http.IValueHttpResult Microsoft.AspNetCore.Http.IValueHttpResult<TValue>可以参考 PR:https://github.com/dotnet/aspnetcore/pull/42385/files
if (result is IValueHttpResult valueHttpResult) return valueHttpResult.Value;也可以使用 IStatusCodeHttpResult 来匹配 response status
if (result is IStatusCodeHttpResult statusCodeResult) return statusCodeResult.StatusCode;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class ApiResultFilter : Attribute , IResultFilter, IExceptionFilter #if NET7_0_OR_GREATER , IEndpointFilter #endif { public void OnResultExecuting(ResultExecutingContext context) { if (context.Result is ObjectResult { Value: not Result } objectResult) { var result = new Result<object>() { Data = objectResult.Value, Status = HttpStatusCode2ResultStatus(objectResult.StatusCode) }; objectResult.Value = result; } } public void OnResultExecuted(ResultExecutedContext context) { } public void OnException(ExceptionContext context) { var result = Result.Fail(context.Exception.ToString(), ResultStatus.ProcessFail); context.Result = new ObjectResult(result) { StatusCode = 500 }; } #if NET7_0_OR_GREATER public async ValueTask<object> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) { try { var result = await next(context); if (result is Result or ObjectResult { Value: Result } or IValueHttpResult { Value: Result }) { return result; } if (result is ObjectResult { Value: not Result } objectResult) { return new Result<object>() { Data = objectResult.Value, Status = HttpStatusCode2ResultStatus(objectResult.StatusCode) }; } if (result is IValueHttpResult { Value: not Result } valueHttpResult) { var status = result is IStatusCodeHttpResult statusCodeHttpResult ? HttpStatusCode2ResultStatus(statusCodeHttpResult.StatusCode) : HttpStatusCode2ResultStatus(200); return new Result<object>() { Data = valueHttpResult.Value, Status = status }; } return new Result<object>() { Data = result, Status = HttpStatusCode2ResultStatus(context.HttpContext.Response.StatusCode) }; } catch (Exception ex) { return Result.Fail(ex.ToString(), ResultStatus.ProcessFail); } } #endif private static ResultStatus HttpStatusCode2ResultStatus(int? statusCode) { statusCode ??= 200; var status = ResultStatus.Success; if (Enum.IsDefined(typeof(ResultStatus), statusCode.Value)) { status = (ResultStatus)statusCode.Value; } if (status == ResultStatus.None) { status = ResultStatus.Success; } return status; } }下面看一个使用的示例:
var app = WebApplication.Create(args); app.Map("/Hello", () => "Hello Minimal API!") .AddEndpointFilter<ApiResultFilter>(); app.Map("/HelloV3", () => Results.Ok(new { Name = "test" })) .AddEndpointFilter<ApiResultFilter>(); app.Map("/HelloV4", () => Results.Ok(Result.Success(new { Name = "test" }))) .AddEndpointFilter<ApiResultFilter>(); await app.RunAsync();访问一个直接返回一个字符串的接口:
[Route("api/[controller]")] public class ValuesController: ControllerBase { [HttpGet("[action]")] public IActionResult Test() { return Ok(new { Name = "Amazing .NET" }); } }
API response 示例: