diff --git a/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Customs/Dtos/WrapResult.cs b/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Customs/Dtos/WrapResult.cs new file mode 100644 index 00000000..9a1b7e20 --- /dev/null +++ b/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Customs/Dtos/WrapResult.cs @@ -0,0 +1,36 @@ +namespace Lion.AbpPro.Extension.Customs.Dtos +{ + public class WrapResult + { + 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; + } + + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Lion.AbpPro.Extension.csproj b/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Lion.AbpPro.Extension.csproj index 740d410a..7de3dcdd 100644 --- a/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Lion.AbpPro.Extension.csproj +++ b/aspnet-core/frameworks/Extensions/src/Lion.AbpPro.Extension/Lion.AbpPro.Extension.csproj @@ -16,5 +16,8 @@ + + + diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/Filters/ResultExceptionFilter.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/Filters/ResultExceptionFilter.cs deleted file mode 100644 index 70211cfb..00000000 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Extensions/Filters/ResultExceptionFilter.cs +++ /dev/null @@ -1,129 +0,0 @@ -// using LionAbpPro.Attributes; -// using Microsoft.AspNetCore.Mvc; -// using Microsoft.AspNetCore.Mvc.Abstractions; -// using Microsoft.AspNetCore.Mvc.Filters; -// using Microsoft.Extensions.DependencyInjection; -// using Microsoft.Extensions.Logging; -// using Microsoft.Extensions.Logging.Abstractions; -// using Microsoft.Extensions.Options; -// using System; -// using System.Linq; -// using System.Text; -// using System.Threading.Tasks; -// using Volo.Abp; -// using Volo.Abp.AspNetCore.ExceptionHandling; -// using Volo.Abp.Authorization; -// using Volo.Abp.DependencyInjection; -// using Volo.Abp.Domain.Entities; -// using Volo.Abp.ExceptionHandling; -// using Volo.Abp.Http; -// using Volo.Abp.Json; -// using Volo.Abp.Validation; -// -// -// namespace LionAbpPro.Extensions.Filters -// { -// public class ResultExceptionFilter : IFilterMetadata, IAsyncExceptionFilter, ITransientDependency -// { -// public ILogger 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 exceptionHandlingOptions) -// { -// _errorInfoConverter = errorInfoConverter; -// _statusCodeFinder = statusCodeFinder; -// _jsonSerializer = jsonSerializer; -// _exceptionHandlingOptions = exceptionHandlingOptions.Value; -// Logger = NullLogger.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(DontWrapResultAttribute), true).Any()) -// { -// return true; -// } -// -// if (context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(DontWrapResultAttribute), true).Any()) -// { -// return true; -// } -// return false; -// } -// -// protected virtual async Task HandleAndWrapException(ExceptionContext context) -// { -// //TODO: Trigger an AbpExceptionHandled event or something like that. -// -// 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(); -// 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() -// .NotifyAsync( -// new ExceptionNotificationContext(context.Exception) -// ); -// -// context.Exception = null; //Handled! -// } -// -// protected 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!"; -// } -// } -// } -// -// } diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj index de0ab7b7..9781b58c 100644 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj +++ b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj @@ -16,4 +16,7 @@ + + + diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/MVC/Filters/ResultExceptionFilter.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/MVC/Filters/ResultExceptionFilter.cs new file mode 100644 index 00000000..1e70e371 --- /dev/null +++ b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/MVC/Filters/ResultExceptionFilter.cs @@ -0,0 +1,128 @@ +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Lion.AbpPro.Extension.Customs.Dtos; +using Volo.Abp; +using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.Authorization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Http; +using Volo.Abp.Json; +using Volo.Abp.Validation; + + +namespace Microsoft.AspNetCore.Mvc.Filters +{ + public class ResultExceptionFilter : IFilterMetadata, IAsyncExceptionFilter, ITransientDependency + { + private ILogger 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 exceptionHandlingOptions) + { + _errorInfoConverter = errorInfoConverter; + _statusCodeFinder = statusCodeFinder; + _jsonSerializer = jsonSerializer; + _exceptionHandlingOptions = exceptionHandlingOptions.Value; + Logger = NullLogger.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) + { + //TODO: Trigger an AbpExceptionHandled event or something like that. + + 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(); + 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() + .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!"; + } + } + } + +} diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/SharedHostingMicroserviceModule.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/SharedHostingMicroserviceModule.cs index 5d2f9e9c..7af6a463 100644 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/SharedHostingMicroserviceModule.cs +++ b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/SharedHostingMicroserviceModule.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -55,6 +56,10 @@ namespace Lion.AbpPro { options.SendExceptionsDetailsToClients = SendExceptionsDetails; }); + context.Services.AddMvc(options => + { + options.Filters.Add(typeof(ResultExceptionFilter)); + }); } /// diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/System/WrapResultAttribute.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/System/WrapResultAttribute.cs new file mode 100644 index 00000000..6b4e7951 --- /dev/null +++ b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/System/WrapResultAttribute.cs @@ -0,0 +1,6 @@ +namespace System +{ + public class WrapResultAttribute : Attribute + { + } +} \ No newline at end of file