From d153bfea1bd8efbd43980aa0e410221ed0b6fb1c Mon Sep 17 00:00:00 2001 From: Berkan Sasmaz Date: Wed, 10 Nov 2021 14:24:32 +0300 Subject: [PATCH] Add an option to AbpExceptionHandlingOptions for enabling/disabling stacktrace --- .../UserExceptionInformer.cs | 6 ++- .../Controllers/ErrorController.cs | 6 ++- .../ExceptionHandling/AbpExceptionFilter.cs | 6 ++- .../AbpExceptionPageFilter.cs | 6 ++- .../AbpExceptionHandlingMiddleware.cs | 8 +++- .../AbpExceptionHandlingOptions.cs | 17 ++++++- .../DefaultExceptionToErrorInfoConverter.cs | 48 +++++++++++++++---- .../IExceptionToErrorInfoConverter.cs | 11 ++++- ...AbpAuthorizationServiceExtensions_Tests.cs | 10 ++-- .../FeatureCheckerExtensions_Tests.cs | 6 +-- ...ureNotEnableException_Localization_Test.cs | 2 +- 11 files changed, 99 insertions(+), 27 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs index 127e3ef0d2..a98628e7dd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs @@ -63,7 +63,11 @@ namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling protected virtual RemoteServiceErrorInfo GetErrorInfo(UserExceptionInformerContext context) { - return ExceptionToErrorInfoConverter.Convert(context.Exception, Options.SendExceptionsDetailsToClients); + return ExceptionToErrorInfoConverter.Convert(context.Exception, options => + { + options.SendExceptionsDetailsToClients = Options.SendExceptionsDetailsToClients; + options.EnableStackTrace = Options.EnableStackTrace; + }); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs index 0b05941f61..365b5479f2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs @@ -47,7 +47,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers await _exceptionNotifier.NotifyAsync(new ExceptionNotificationContext(exception)); - var errorInfo = _errorInfoConverter.Convert(exception, _exceptionHandlingOptions.SendExceptionsDetailsToClients); + var errorInfo = _errorInfoConverter.Convert(exception, options => + { + options.SendExceptionsDetailsToClients = _exceptionHandlingOptions.SendExceptionsDetailsToClients; + options.EnableStackTrace = _exceptionHandlingOptions.EnableStackTrace; + }); if (httpStatusCode == 0) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index 9631e94da4..0b43ead885 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -59,7 +59,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling var exceptionHandlingOptions = context.GetRequiredService>().Value; var exceptionToErrorInfoConverter = context.GetRequiredService(); - var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); + var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => + { + options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; + options.EnableStackTrace = exceptionHandlingOptions.EnableStackTrace; + }); var logLevel = context.Exception.GetLogLevel(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index 2a8c136fbc..b0925facc4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -71,7 +71,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling var exceptionHandlingOptions = context.GetRequiredService>().Value; var exceptionToErrorInfoConverter = context.GetRequiredService(); - var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); + var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => + { + options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; + options.EnableStackTrace = exceptionHandlingOptions.EnableStackTrace; + }); var logLevel = context.Exception.GetLogLevel(); diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index 51c78b4a83..491501720a 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -76,7 +76,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling var errorInfoConverter = httpContext.RequestServices.GetRequiredService(); var statusCodeFinder = httpContext.RequestServices.GetRequiredService(); var jsonSerializer = httpContext.RequestServices.GetRequiredService(); - var options = httpContext.RequestServices.GetRequiredService>().Value; + var exceptionHandlingOptions = httpContext.RequestServices.GetRequiredService>().Value; httpContext.Response.Clear(); httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception); @@ -86,7 +86,11 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling await httpContext.Response.WriteAsync( jsonSerializer.Serialize( new RemoteServiceErrorResponse( - errorInfoConverter.Convert(exception, options.SendExceptionsDetailsToClients) + errorInfoConverter.Convert(exception, options => + { + options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; + options.EnableStackTrace = exceptionHandlingOptions.EnableStackTrace; + }) ) ) ); diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingOptions.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingOptions.cs index 0cfdb8089d..8a66da1a86 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingOptions.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingOptions.cs @@ -2,6 +2,21 @@ { public class AbpExceptionHandlingOptions { - public bool SendExceptionsDetailsToClients { get; set; } = false; + public bool SendExceptionsDetailsToClients { get; set; } + + private bool _enableStackTrace; + + public bool EnableStackTrace + { + get => _enableStackTrace; + set + { + _enableStackTrace = value; + if (_enableStackTrace) + { + SendExceptionsDetailsToClients = true; + } + } + } } } diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index eeddb2e9be..24251731a5 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -40,7 +40,11 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling public RemoteServiceErrorInfo Convert(Exception exception, bool includeSensitiveDetails) { - var errorInfo = CreateErrorInfoWithoutCode(exception, includeSensitiveDetails); + var exceptionHandlingOptions = CreateDefaultOptions(); + exceptionHandlingOptions.SendExceptionsDetailsToClients = includeSensitiveDetails; + exceptionHandlingOptions.EnableStackTrace = includeSensitiveDetails; + + var errorInfo = CreateErrorInfoWithoutCode(exception, exceptionHandlingOptions); if (exception is IHasErrorCode hasErrorCodeException) { @@ -50,11 +54,26 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return errorInfo; } - protected virtual RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception, bool includeSensitiveDetails) + public RemoteServiceErrorInfo Convert(Exception exception, Action options = null) { - if (includeSensitiveDetails) + var exceptionHandlingOptions = CreateDefaultOptions(); + options?.Invoke(exceptionHandlingOptions); + + var errorInfo = CreateErrorInfoWithoutCode(exception, exceptionHandlingOptions); + + if (exception is IHasErrorCode hasErrorCodeException) + { + errorInfo.Code = hasErrorCodeException.Code; + } + + return errorInfo; + } + + protected virtual RemoteServiceErrorInfo CreateErrorInfoWithoutCode(Exception exception, AbpExceptionHandlingOptions options) + { + if (options.SendExceptionsDetailsToClients) { - return CreateDetailedErrorInfoFromException(exception); + return CreateDetailedErrorInfoFromException(exception, options.EnableStackTrace); } exception = TryToGetActualException(exception); @@ -194,11 +213,11 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return exception; } - protected virtual RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception) + protected virtual RemoteServiceErrorInfo CreateDetailedErrorInfoFromException(Exception exception, bool enableStackTrace) { var detailBuilder = new StringBuilder(); - AddExceptionToDetails(exception, detailBuilder); + AddExceptionToDetails(exception, detailBuilder, enableStackTrace); var errorInfo = new RemoteServiceErrorInfo(exception.Message, detailBuilder.ToString()); @@ -210,7 +229,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return errorInfo; } - protected virtual void AddExceptionToDetails(Exception exception, StringBuilder detailBuilder) + protected virtual void AddExceptionToDetails(Exception exception, StringBuilder detailBuilder, bool enableStackTrace) { //Exception Message detailBuilder.AppendLine(exception.GetType().Name + ": " + exception.Message); @@ -237,7 +256,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling } //Exception StackTrace - if (!string.IsNullOrEmpty(exception.StackTrace)) + if (enableStackTrace && !string.IsNullOrEmpty(exception.StackTrace)) { detailBuilder.AppendLine("STACK TRACE: " + exception.StackTrace); } @@ -245,7 +264,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling //Inner exception if (exception.InnerException != null) { - AddExceptionToDetails(exception.InnerException, detailBuilder); + AddExceptionToDetails(exception.InnerException, detailBuilder, enableStackTrace); } //Inner exceptions for AggregateException @@ -259,7 +278,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling foreach (var innerException in aggException.InnerExceptions) { - AddExceptionToDetails(innerException, detailBuilder); + AddExceptionToDetails(innerException, detailBuilder, enableStackTrace); } } } @@ -296,5 +315,14 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling return detailBuilder.ToString(); } + + protected virtual AbpExceptionHandlingOptions CreateDefaultOptions() + { + return new AbpExceptionHandlingOptions + { + SendExceptionsDetailsToClients = false, + EnableStackTrace = false + }; + } } } diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs index 3293be71ee..44aaec0845 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs @@ -12,9 +12,18 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling /// /// Converter method. /// - /// The exception + /// The exception. /// Should include sensitive details to the error info? /// Error info or null + [Obsolete("Use other Convert method.")] RemoteServiceErrorInfo Convert(Exception exception, bool includeSensitiveDetails); + + /// + /// Converter method. + /// + /// The exception. + /// Additional options. + /// Error info or null + RemoteServiceErrorInfo Convert(Exception exception, Action options = null); } } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions_Tests.cs index e8876aaebf..0d3ebfa08a 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions_Tests.cs @@ -21,27 +21,27 @@ namespace Microsoft.AspNetCore.Authorization using (CultureHelper.Use("zh-Hans")) { var exception = new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGranted); - var errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + var errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("授权失败! 提供的策略尚未授予."); exception = new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGrantedWithPolicyName) .WithData("PolicyName", "my_policy_name"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("授权失败! 提供的策略尚未授予: my_policy_name"); exception = new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGrantedForGivenResource) .WithData("ResourceName", "my_resource_name"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("授权失败! 提供的策略未授予提供的资源: my_resource_name"); exception = new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenRequirementHasNotGrantedForGivenResource) .WithData("ResourceName", "my_resource_name"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("授权失败! 提供的要求未授予提供的资源: my_resource_name"); exception = new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenRequirementsHasNotGrantedForGivenResource) .WithData("ResourceName", "my_resource_name"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("授权失败! 提供的要求未授予提供的资源: my_resource_name"); } } diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureCheckerExtensions_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureCheckerExtensions_Tests.cs index 0df9548f3c..fd116217d4 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureCheckerExtensions_Tests.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureCheckerExtensions_Tests.cs @@ -22,17 +22,17 @@ namespace Volo.Abp.Features { var exception = new AbpAuthorizationException(code: AbpFeatureErrorCodes.FeatureIsNotEnabled) .WithData("FeatureName", "my_feature_name"); - var errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + var errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("功能未启用: my_feature_name"); exception = new AbpAuthorizationException(code: AbpFeatureErrorCodes.AllOfTheseFeaturesMustBeEnabled) .WithData("FeatureNames", "my_feature_name, my_feature_name2"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("必要的功能未启用. 这些功能需要启用: my_feature_name, my_feature_name2"); exception = new AbpAuthorizationException(code: AbpFeatureErrorCodes.AtLeastOneOfTheseFeaturesMustBeEnabled) .WithData("FeatureNames", "my_feature_name, my_feature_name2"); - errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("必要的功能未启用. 需要启用这些功能中的一项:my_feature_name, my_feature_name2"); } } diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/AbpGlobalFeatureNotEnableException_Localization_Test.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/AbpGlobalFeatureNotEnableException_Localization_Test.cs index c638f03d46..b30fad3195 100644 --- a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/AbpGlobalFeatureNotEnableException_Localization_Test.cs +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/AbpGlobalFeatureNotEnableException_Localization_Test.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.GlobalFeatures var exception = new AbpGlobalFeatureNotEnabledException(code: AbpGlobalFeatureErrorCodes.GlobalFeatureIsNotEnabled) .WithData("ServiceName", "MyService") .WithData("GlobalFeatureName", "TestFeature");; - var errorInfo = _exceptionToErrorInfoConverter.Convert(exception, false); + var errorInfo = _exceptionToErrorInfoConverter.Convert(exception); errorInfo.Message.ShouldBe("'MyService'服务需要启用'TestFeature'功能."); } }