我有一个简单的API控制器方法
public async Task<Models.Timesheet> GetByDate(DateTime date, string user = null)
{
throw new InvalidOperationException();
}
现在的问题是,我在自定义操作过滤器中或通过设置IncludeErrorDetailPolicy.Always
得到的异常堆栈跟踪就像这样
System.InvalidOperationException: Operation is not valid due to the current state of the object.
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.ApiController.<InvokeActionWithExceptionFilters>d__1.MoveNext()
Web API v1曾经好多了。在升级到v2之后,堆栈跟踪几乎无法使用 - 预计使用async / await时,堆栈跟踪将不会像过去那样,但在这种情况下,整个堆栈跟踪不包括任何提示,即使是类失败。是否可以在Web API中配置某些内容以缓解此问题?
答案 0 :(得分:7)
WebApi 2.1(程序集版本5.1.1)
中已修复此问题按照以下说明升级到最新版本:https://www.nuget.org/packages/Microsoft.AspNet.WebApi
答案 1 :(得分:4)
因此,在我提出问题之后,我有正确的动机来正确挖掘Web API代码以找到问题。似乎罪魁祸首是ActionFilterAttribute.CallOnActionExecutedAsync
方法做了这样的事情(释义,而不是实际的代码):
try
{
await previous();
}
catch(Exception ex)
{
exception = ex;
}
var context = new HttpActionExecutedContext(actionContext, exception);
this.OnActionExecuted(context);
if (context.Response == null && context.Exception != null)
throw context.Exception;
所以碰巧第一个过滤器实际上获得了正确的堆栈跟踪。但是它只是去重新抛出异常,从而失去了原始的堆栈跟踪。
这让我意识到,我需要从ExceptionFilterAttribute
派生而不是从ActionFilterAttribute
派生,因为前者总是被称为最后。不幸的是,我还需要确保我的异常过滤器首先运行,但这不是内置的Web API(see this question以获得正确的解决方案)。
我的快速解决方案是确保我在应用程序中拥有的所有过滤器(我只有几个)派生自我的自定义异常过滤器(并调用base.OnActionExecuted()
),因此每个过滤器都会实际检查异常并且执行类似这样的事情:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Exception == null)
return;
WriteLog(actionExecutedContext.Exception);
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(
System.Net.HttpStatusCode.InternalServerError,
actionExecutedContext.Exception.Message,
actionExecutedContext.Exception);
actionExecutedContext.Exception = null;
}
通过这种解决方法,如果启用了错误详细信息,我会在日志和用户中获得正确的堆栈跟踪。
答案 2 :(得分:1)
我相信在Windows 8.1 / Server 2012 R2上运行时,.NET 4.5.1上的堆栈跟踪得到了改进。
或者,我确实有一个"Async Diagnostics" NuGet package可以安装到您的项目中。然后添加以下行:
[assembly: AsyncDiagnosticAspect]
您可以在ToAsyncDiagnosticString
类型上使用Exception
扩展方法。 ToAsyncDiagnosticString
包含来自ToString
的所有信息,然后附加“逻辑堆栈”。更多文档(和来源)on GitHub。
请注意,不支持部分信任,这在Debug版本中效果最佳。