|
|
|
@ -59,117 +59,35 @@ 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<IOptions<AbpExceptionHandlingOptions>>().Value; |
|
|
|
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>(); |
|
|
|
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => |
|
|
|
{ |
|
|
|
options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; |
|
|
|
options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients; |
|
|
|
}); |
|
|
|
- [LionExceptionFilter](https://github.com/WangJunZzz/abp-vnext-pro/blob/main/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/LionExceptionFilter.cs) |
|
|
|
|
|
|
|
var logLevel = context.Exception.GetLogLevel(); |
|
|
|
- 添加结果过滤器 |
|
|
|
- [LionResultFilter](https://github.com/WangJunZzz/abp-vnext-pro/blob/main/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/LionResultFilter.cs) |
|
|
|
|
|
|
|
var remoteServiceErrorInfoBuilder = new StringBuilder(); |
|
|
|
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); |
|
|
|
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true)); |
|
|
|
|
|
|
|
var logger = context.GetService<ILogger<ResultExceptionFilter>>(NullLogger<ResultExceptionFilter>.Instance); |
|
|
|
|
|
|
|
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); |
|
|
|
|
|
|
|
logger.LogException(context.Exception, logLevel); |
|
|
|
|
|
|
|
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception)); |
|
|
|
context.HttpContext.Response.StatusCode = 200; |
|
|
|
var result = SimplifyMessage(context); |
|
|
|
context.Result = new ObjectResult(result); |
|
|
|
context.Exception = null; //Handled! |
|
|
|
} |
|
|
|
## 注册 Filter |
|
|
|
|
|
|
|
private WrapResult<object> SimplifyMessage(ExceptionContext context) |
|
|
|
{ |
|
|
|
var result = new WrapResult<object>(); |
|
|
|
var localizer = context.GetService<IStringLocalizer<AbpProResource>>(); |
|
|
|
switch (context.Exception) |
|
|
|
```csharp |
|
|
|
/// <summary> |
|
|
|
/// 异常处理 |
|
|
|
/// </summary> |
|
|
|
private void ConfigureAbpExceptions(ServiceConfigurationContext context) |
|
|
|
{ |
|
|
|
context.Services.AddMvc |
|
|
|
( |
|
|
|
options => |
|
|
|
{ |
|
|
|
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; |
|
|
|
} |
|
|
|
options.Filters.Add(typeof(LionExceptionFilter)); |
|
|
|
options.Filters.Add(typeof(LionResultFilter)); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
## 注册 Filter |
|
|
|
|
|
|
|
```csharp |
|
|
|
public override void ConfigureServices(ServiceConfigurationContext context) |
|
|
|
{ |
|
|
|
context.Services.AddMvc(options => |
|
|
|
{ |
|
|
|
options.Filters.Add(typeof(ResultExceptionFilter)); |
|
|
|
}); |
|
|
|
} |
|
|
|
public override void ConfigureServices(ServiceConfigurationContext context) |
|
|
|
{ |
|
|
|
ConfigureAbpExceptions(context); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
## 使用 |
|
|
|
@ -199,3 +117,5 @@ public sealed class ResultExceptionFilter : IAsyncExceptionFilter, ITransientDep |
|
|
|
|
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
- 不管接口时有异常还是成功返回结果都是 WrapResult,PermissionOutput 在 WrapResult.Data 中。 |
|
|
|
|