Abp Vnext 中如何統一介面返回值
阿新 • • 發佈:2021-11-28
ABP Vnext Vue 的實現
-
在使用 abp 的過程中,如果提供給第三方介面要實現返回值統一需要怎麼做?
{
// 返回格式類似這種
"success": false,
"message": "請求失敗",
"data": null,
"code": 500
}
- 定義返回型別
public class WrapResult<T> { private bool Success { get; set; } private string Message { get; set; } private T Data { get; set; } private int Code { get; 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
public class WrapResultAttribute : Attribute
{
}
- 實現 IAsyncExceptionFilter(攔截異常,拋異常時指定返回格式)
public class ResultExceptionFilter : IFilterMetadata, IAsyncExceptionFilter, ITransientDependency { private ILogger<ResultExceptionFilter> Logger { get; set; } private readonly IExceptionToErrorInfoConverter _errorInfoConverter; private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder; private readonly IJsonSerializer _jsonSerializer; private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions; public ResultExceptionFilter( IExceptionToErrorInfoConverter errorInfoConverter, IHttpExceptionStatusCodeFinder statusCodeFinder, IJsonSerializer jsonSerializer, IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions) { _errorInfoConverter = errorInfoConverter; _statusCodeFinder = statusCodeFinder; _jsonSerializer = jsonSerializer; _exceptionHandlingOptions = exceptionHandlingOptions.Value; Logger = NullLogger<ResultExceptionFilter>.Instance; } public async Task OnExceptionAsync(ExceptionContext context) { if (!ShouldHandleException(context)) { return; } await HandleAndWrapException(context); } protected virtual 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; } protected virtual async Task HandleAndWrapException(ExceptionContext context) { // 處理異常資訊 context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); var statusCode = (int)_statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception); context.HttpContext.Response.StatusCode = 200; var remoteServiceErrorInfo = _errorInfoConverter.Convert(context.Exception, _exceptionHandlingOptions.SendExceptionsDetailsToClients); remoteServiceErrorInfo.Code = context.HttpContext.TraceIdentifier; remoteServiceErrorInfo.Message = SimplifyMessage(context.Exception); // 返回格式統一 var result = new WrapResult<object>(); result.SetFail(remoteServiceErrorInfo.Message); // HttpResponse context.Result = new ObjectResult(result); // 寫日誌 var logLevel = context.Exception.GetLogLevel(); var remoteServiceErrorInfoBuilder = new StringBuilder(); remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); remoteServiceErrorInfoBuilder.AppendLine(_jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); Logger.LogException(context.Exception, logLevel); await context.HttpContext .RequestServices .GetRequiredService<IExceptionNotifier>() .NotifyAsync( new ExceptionNotificationContext(context.Exception) ); context.Exception = null; //Handled! } private string SimplifyMessage(Exception error) { string message = string.Empty; switch (error) { case AbpAuthorizationException e: return message = "Authenticate failure!"; case AbpValidationException e: return message = "Request param validate failure!"; case EntityNotFoundException e: return message = "not found the entity!"; case BusinessException e: return message = $"{e.Message}"; case NotImplementedException e: return message = "not implement!"; default: return message = "server internal error!"; } } }
註冊 Filter
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMvc(options =>
{
options.Filters.Add(typeof(ResultExceptionFilter));
});
}
使用
- 在 Controller 上或者 Action 上打上 WrapResultAttribute 特性
- 例如
[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<PermissionOutput> GetPermissionAsync(GetPermissionInput input) { return _rolePermissionAppService.GetPermissionAsync(input); } }