# 统一返回值格式 - 在使用 abp 的过程中,如果提供给第三方接口要实现返回值统一需要怎么做? ```csharp { // 返回格式类似这种 "success": false, "message": "请求失败", "data": null, "code": 500 } ``` - 定义返回类型 ```csharp public class WrapResult { public bool Success { get; private set; } public string Message { get; private set; } public T Data { get; private set; } public int Code { get; private set; } public WrapResult() { Success = true; Message = "Success"; Data = default; Code = 200; } public void SetSuccess(T data, string message = "Success", int code = 200) { Success = true; Data = data; Code = code; } public void SetFail(string message = "Fail", int code = 500) { Success = false; Message = message; Code = code; } } ``` ## 实现思路 - 定义 WrapResultAttribute ```csharp public class WrapResultAttribute : Attribute { } ``` - 实现 IAsyncExceptionFilter(拦截异常,抛异常时指定返回格式) ```csharp public sealed class ResultExceptionFilter : IAsyncExceptionFilter, ITransientDependency { public async Task OnExceptionAsync(ExceptionContext context) { if (!ShouldHandleException(context)) { return; } await HandleAndWrapException(context); } private bool ShouldHandleException(ExceptionContext context) { if (context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(WrapResultAttribute), true).Any()) { return true; } if (context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(WrapResultAttribute), true).Any()) { return true; } return false; } private async Task HandleAndWrapException(ExceptionContext context) { var exceptionHandlingOptions = context.GetRequiredService>().Value; var exceptionToErrorInfoConverter = context.GetRequiredService(); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => { options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients; }); var logLevel = context.Exception.GetLogLevel(); var remoteServiceErrorInfoBuilder = new StringBuilder(); remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService().Serialize(remoteServiceErrorInfo, indented: true)); var logger = context.GetService>(NullLogger.Instance); logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); logger.LogException(context.Exception, logLevel); await context.GetRequiredService().NotifyAsync(new ExceptionNotificationContext(context.Exception)); context.HttpContext.Response.StatusCode = 200; var result = SimplifyMessage(context); context.Result = new ObjectResult(result); context.Exception = null; //Handled! } private WrapResult SimplifyMessage(ExceptionContext context) { var result = new WrapResult(); var localizer = context.GetService>(); switch (context.Exception) { case AbpAuthorizationException: result.SetFail("权限不足", 401); break; case AbpValidationException: result.SetFail("请求参数验证失败", 400); break; case EntityNotFoundException: result.SetFail("实体不存在", 506); break; case NotImplementedException: result.SetFail("未实现功能", 507); break; default: { if (context.Exception is IHasErrorCode codeException) { result.SetFail(localizer[codeException.Code]); foreach (var key in context.Exception.Data.Keys) { result.SetFail(result.Message.Replace("{" + key + "}", context.Exception.Data[key]?.ToString())); } } else { result.SetFail(context.Exception.Message); } break; } } return result; } } ``` ## 注册 Filter ```csharp public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddMvc(options => { options.Filters.Add(typeof(ResultExceptionFilter)); }); } ``` ## 使用 - 在 Controller 上或者 Action 上打上 WrapResultAttribute 特性 - 例如 ```csharp [Route("Permissions")] [WrapResult] public class PermissionController : AbpProController,IRolePermissionAppService { private readonly IRolePermissionAppService _rolePermissionAppService; public PermissionController(IRolePermissionAppService rolePermissionAppService) { _rolePermissionAppService = rolePermissionAppService; } [HttpPost("tree")] [SwaggerOperation(summary: "获取角色权限", Tags = new[] { "Permissions" })] [WrapResult] //控制器上打了 action上就不需要 public Task GetPermissionAsync(GetPermissionInput input) { return _rolePermissionAppService.GetPermissionAsync(input); } } ```