Browse Source

🚑 统一参数返回值过滤器,空指针异常 #61

IdentityServer4
WangJunZzz 4 years ago
parent
commit
1c2fea18dd
  1. 8
      aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Customs/Dtos/WrapResult.cs
  2. 128
      aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/MVC/Filters/ResultExceptionFilter.cs
  3. 2
      aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/System/DontWrapResultAttribute.cs
  4. 3
      aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs

8
aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Customs/Dtos/WrapResult.cs

@ -2,13 +2,13 @@
{ {
public class WrapResult<T> public class WrapResult<T>
{ {
private bool Success { get; set; } public bool Success { get; set; }
private string Message { get; set; } public string Message { get; set; }
private T Data { get; set; } public T Data { get; set; }
private int Code { get; set; } public int Code { get; set; }
public WrapResult() public WrapResult()
{ {

128
aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/MVC/Filters/ResultExceptionFilter.cs

@ -1,27 +1,7 @@
namespace Lion.AbpPro.Shared.Hosting.Microservices.Microsoft.AspNetCore.MVC.Filters namespace Lion.AbpPro.Extensions.MVC.Filters
{ {
public sealed class ResultExceptionFilter : IFilterMetadata, IAsyncExceptionFilter, ITransientDependency public sealed class ResultExceptionFilter : 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) public async Task OnExceptionAsync(ExceptionContext context)
{ {
if (!ShouldHandleException(context)) if (!ShouldHandleException(context))
@ -29,78 +9,96 @@ namespace Lion.AbpPro.Shared.Hosting.Microservices.Microsoft.AspNetCore.MVC.Filt
return; return;
} }
await HandleAndWrapException(context); await HandleAndWrapException(context);
} }
private bool ShouldHandleException(ExceptionContext context) private bool ShouldHandleException(ExceptionContext context)
{ {
if (context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(WrapResultAttribute), true).Any()) if (context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(DontWrapResultAttribute), true).Any())
{ {
return true; return true;
} }
if (context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(WrapResultAttribute), true).Any()) if (context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(DontWrapResultAttribute), true).Any())
{ {
return true; return true;
} }
return false; return false;
} }
private async Task HandleAndWrapException(ExceptionContext context) private async Task HandleAndWrapException(ExceptionContext context)
{ {
//TODO: Trigger an AbpExceptionHandled event or something like that. var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true"); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options =>
var statusCode = (int)_statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception); {
context.HttpContext.Response.StatusCode = 200; options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients;
options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients;
var remoteServiceErrorInfo = _errorInfoConverter.Convert(context.Exception, options => { options.SendExceptionsDetailsToClients = _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 logLevel = context.Exception.GetLogLevel();
var remoteServiceErrorInfoBuilder = new StringBuilder(); var remoteServiceErrorInfoBuilder = new StringBuilder();
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
remoteServiceErrorInfoBuilder.AppendLine(_jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true));
Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
Logger.LogException(context.Exception, logLevel); var logger = context.GetService<ILogger<ResultExceptionFilter>>(NullLogger<ResultExceptionFilter>.Instance);
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
await context.HttpContext logger.LogException(context.Exception, logLevel);
.RequestServices
.GetRequiredService<IExceptionNotifier>()
.NotifyAsync(
new ExceptionNotificationContext(context.Exception)
);
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! context.Exception = null; //Handled!
} }
private string SimplifyMessage(Exception error) private WrapResult<object> SimplifyMessage(ExceptionContext context)
{ {
switch (error) var result = new WrapResult<object>();
var localizer = context.GetService<IStringLocalizer<AbpProResource>>();
switch (context.Exception)
{ {
case AbpAuthorizationException e: case AbpAuthorizationException:
return "Authenticate failure!"; result.Code = 401;
case AbpValidationException e: result.Message = "权限不足.";
return "Request param validate failure!"; break;
case EntityNotFoundException e: case AbpValidationException:
return "not found the entity!"; result.Code = 400;
case BusinessException e: result.Message = "请求参数验证失败.";
return $"{e.Message}"; break;
case NotImplementedException e: case EntityNotFoundException:
return "not implement!"; result.Code = 506;
result.Message = "实体不存在.";
break;
case NotImplementedException:
result.Code = 507;
result.Message = "未实现功能.";
break;
default: default:
return "server internal error!"; {
result.Code = 500;
if (context.Exception is IHasErrorCode codeException)
{
result.Message = localizer[codeException.Code];
foreach (var key in context.Exception.Data.Keys)
{
result.Message = result.Message.Replace("{" + key + "}", context.Exception.Data[key]?.ToString());
}
}
else
{
result.Message = context.Exception.Message;
}
break;
}
} }
return result;
} }
} }
}
}

2
aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/System/WrapResultAttribute.cs → aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/System/DontWrapResultAttribute.cs

@ -1,6 +1,6 @@
namespace Lion.AbpPro.Extensions.System namespace Lion.AbpPro.Extensions.System
{ {
public class WrapResultAttribute : Attribute public class DontWrapResultAttribute : Attribute
{ {
} }
} }

3
aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs

@ -20,12 +20,12 @@ global using Lion.AbpPro.Extension.Customs.Dtos;
global using Lion.AbpPro.Extensions; global using Lion.AbpPro.Extensions;
global using Lion.AbpPro.Extensions.Hangfire; global using Lion.AbpPro.Extensions.Hangfire;
global using Lion.AbpPro.Extensions.Middlewares; global using Lion.AbpPro.Extensions.Middlewares;
global using Lion.AbpPro.Extensions.MVC.Filters;
global using Lion.AbpPro.Extensions.System; global using Lion.AbpPro.Extensions.System;
global using Lion.AbpPro.Localization; global using Lion.AbpPro.Localization;
global using Lion.AbpPro.MultiTenancy; global using Lion.AbpPro.MultiTenancy;
global using Lion.AbpPro.Shared.Hosting.Microservices; global using Lion.AbpPro.Shared.Hosting.Microservices;
global using Lion.AbpPro.Shared.Hosting.Microservices.Microsoft.AspNetCore.Builder; global using Lion.AbpPro.Shared.Hosting.Microservices.Microsoft.AspNetCore.Builder;
global using Lion.AbpPro.Shared.Hosting.Microservices.Microsoft.AspNetCore.MVC.Filters;
global using Lion.AbpPro.Shared.Hosting.Microservices.Swaggers; global using Lion.AbpPro.Shared.Hosting.Microservices.Swaggers;
global using Magicodes.ExporterAndImporter.Core; global using Magicodes.ExporterAndImporter.Core;
global using Magicodes.ExporterAndImporter.Excel; global using Magicodes.ExporterAndImporter.Excel;
@ -41,6 +41,7 @@ global using Microsoft.AspNetCore.Mvc.Filters;
global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Localization;
global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Logging.Abstractions; global using Microsoft.Extensions.Logging.Abstractions;
global using Microsoft.Extensions.Options; global using Microsoft.Extensions.Options;

Loading…
Cancel
Save