From 7a71f64978345f10f41893847c1961dea61cae79 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 12 Sep 2017 21:54:55 +1000 Subject: [PATCH] U4-10407 We should log unhandled exceptions that occur in webapi controllers and always have detailed errors returned to users even when not in debug mode --- .../src/common/services/formhelper.service.js | 4 +-- src/Umbraco.Web/Umbraco.Web.csproj | 3 ++ .../WebApi/EnableDetailedErrorsAttribute.cs | 17 +++++++++ .../WebApi/UmbracoAuthorizedApiController.cs | 4 ++- ...edExceptionLoggerConfigurationAttribute.cs | 29 +++++++++++++++ .../WebApi/UnhandledExceptionLogger.cs | 36 +++++++++++++++++++ 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web/WebApi/EnableDetailedErrorsAttribute.cs create mode 100644 src/Umbraco.Web/WebApi/UnhandedExceptionLoggerConfigurationAttribute.cs create mode 100644 src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs diff --git a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js index 5d5b509315..21c7742c61 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js @@ -150,9 +150,7 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati dialogService.ysodDialog(err); } } - else { - dialogService.ysodDialog(err); - } + }, /** diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index abe4bbc7cf..c86b86db30 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -782,6 +782,7 @@ + @@ -1225,6 +1226,8 @@ + + diff --git a/src/Umbraco.Web/WebApi/EnableDetailedErrorsAttribute.cs b/src/Umbraco.Web/WebApi/EnableDetailedErrorsAttribute.cs new file mode 100644 index 0000000000..1d35d19134 --- /dev/null +++ b/src/Umbraco.Web/WebApi/EnableDetailedErrorsAttribute.cs @@ -0,0 +1,17 @@ +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; + +namespace Umbraco.Web.WebApi +{ + /// + /// Ensures controllers have detailed error messages even when debug mode is off + /// + public class EnableDetailedErrorsAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(HttpActionContext actionContext) + { + actionContext.ControllerContext.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 25f85def0f..73f6367741 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -22,7 +22,9 @@ namespace Umbraco.Web.WebApi [UmbracoAuthorize] [DisableBrowserCache] [UmbracoWebApiRequireHttps] - [CheckIfUserTicketDataIsStale] + [CheckIfUserTicketDataIsStale] + [UnhandedExceptionLoggerConfiguration] + [EnableDetailedErrors] public abstract class UmbracoAuthorizedApiController : UmbracoApiController { diff --git a/src/Umbraco.Web/WebApi/UnhandedExceptionLoggerConfigurationAttribute.cs b/src/Umbraco.Web/WebApi/UnhandedExceptionLoggerConfigurationAttribute.cs new file mode 100644 index 0000000000..51c43b0821 --- /dev/null +++ b/src/Umbraco.Web/WebApi/UnhandedExceptionLoggerConfigurationAttribute.cs @@ -0,0 +1,29 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Http.Controllers; +using System.Web.Http.ExceptionHandling; +using System.Web.Http.Filters; +using Umbraco.Core; +using Umbraco.Core.Logging; + +namespace Umbraco.Web.WebApi +{ + /// + /// Adds our unhandled exception logger to the controller's services + /// + /// + /// Important to note that the will only be called if the controller has an ExceptionFilter applied + /// to it, so to kill two birds with one stone, this class inherits from ExceptionFilterAttribute purely to force webapi to use the + /// IExceptionLogger (strange) + /// + public class UnhandedExceptionLoggerConfigurationAttribute : ExceptionFilterAttribute, IControllerConfiguration + { + public virtual void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) + { + controllerSettings.Services.Add(typeof(IExceptionLogger), new UnhandledExceptionLogger()); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs b/src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs new file mode 100644 index 0000000000..7c6d9df294 --- /dev/null +++ b/src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs @@ -0,0 +1,36 @@ +using System.Web.Http.ExceptionHandling; +using Umbraco.Core; +using Umbraco.Core.Logging; + +namespace Umbraco.Web.WebApi +{ + /// + /// Used to log unhandled exceptions in webapi controllers + /// + public class UnhandledExceptionLogger : ExceptionLogger + { + private readonly ILogger _logger; + + public UnhandledExceptionLogger() + : this(ApplicationContext.Current.ProfilingLogger.Logger) + { + } + + public UnhandledExceptionLogger(ILogger logger) + { + _logger = logger; + } + + public override void Log(ExceptionLoggerContext context) + { + if (context != null && context.ExceptionContext != null + && context.ExceptionContext.ActionContext != null && context.ExceptionContext.ActionContext.ControllerContext != null + && context.ExceptionContext.ActionContext.ControllerContext.Controller != null + && context.Exception != null) + { + _logger.Error(context.ExceptionContext.ActionContext.ControllerContext.Controller.GetType(), "Unhandled controller exception occurred", context.Exception); + } + } + + } +} \ No newline at end of file