Merge pull request #2189 from umbraco/temp-U4-10407

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
This commit is contained in:
Sebastiaan Janssen
2017-09-13 12:04:29 +02:00
committed by GitHub
6 changed files with 89 additions and 4 deletions

View File

@@ -150,9 +150,7 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
dialogService.ysodDialog(err);
}
}
else {
dialogService.ysodDialog(err);
}
},
/**

View File

@@ -782,6 +782,7 @@
<Compile Include="WebApi\AngularJsonMediaTypeFormatter.cs" />
<Compile Include="WebApi\AngularJsonOnlyConfigurationAttribute.cs" />
<Compile Include="WebApi\Binders\MemberBinder.cs" />
<Compile Include="WebApi\EnableDetailedErrorsAttribute.cs" />
<Compile Include="WebApi\Filters\AngularAntiForgeryHelper.cs" />
<Compile Include="WebApi\Filters\AppendCurrentEventMessagesAttribute.cs" />
<Compile Include="WebApi\Filters\AppendUserModifiedHeaderAttribute.cs" />
@@ -1225,6 +1226,8 @@
<Compile Include="WebApi\UmbracoAuthorizedApiController.cs" />
<Compile Include="WebApi\Filters\ValidationFilterAttribute.cs" />
<Compile Include="WebApi\Filters\UmbracoUserTimeoutFilterAttribute.cs" />
<Compile Include="WebApi\UnhandedExceptionLoggerConfigurationAttribute.cs" />
<Compile Include="WebApi\UnhandledExceptionLogger.cs" />
<Compile Include="WebApi\WebApiHelper.cs" />
<Compile Include="WebBootManager.cs" />
<Compile Include="Routing\LegacyRequestInitializer.cs" />

View File

@@ -0,0 +1,17 @@
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Umbraco.Web.WebApi
{
/// <summary>
/// Ensures controllers have detailed error messages even when debug mode is off
/// </summary>
public class EnableDetailedErrorsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
actionContext.ControllerContext.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
}
}

View File

@@ -22,7 +22,9 @@ namespace Umbraco.Web.WebApi
[UmbracoAuthorize]
[DisableBrowserCache]
[UmbracoWebApiRequireHttps]
[CheckIfUserTicketDataIsStale]
[CheckIfUserTicketDataIsStale]
[UnhandedExceptionLoggerConfiguration]
[EnableDetailedErrors]
public abstract class UmbracoAuthorizedApiController : UmbracoApiController
{

View File

@@ -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
{
/// <summary>
/// Adds our unhandled exception logger to the controller's services
/// </summary>
/// <remarks>
/// Important to note that the <see cref="UnhandledExceptionLogger"/> 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)
/// </remarks>
public class UnhandedExceptionLoggerConfigurationAttribute : ExceptionFilterAttribute, IControllerConfiguration
{
public virtual void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Add(typeof(IExceptionLogger), new UnhandledExceptionLogger());
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Web.Http.ExceptionHandling;
using Umbraco.Core;
using Umbraco.Core.Logging;
namespace Umbraco.Web.WebApi
{
/// <summary>
/// Used to log unhandled exceptions in webapi controllers
/// </summary>
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);
}
}
}
}