调试异步代码中的异常

时间:2013-12-20 00:54:14

标签: c# asp.net .net asp.net-web-api async-await

当我在使用ASP.NET MVC 3的代码中使用同步方法时,如果抛出异常,则在我的异常过滤器中找出它的位置并不难。只看堆栈跟踪就足够了。

但是,如果ASP.NET Web API中的async方法抛出异常,则异常详细信息不太有用,因为堆栈跟踪不会显示抛出异常的位置:

System.ArgumentException: title must not be empty.
Parameter name: title    
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.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()

目前,我必须查看此消息的所有异常,并根据请求URI以及幕后发生的情况猜测哪一个被抛出,或尝试使用附加的调试器在本地重现该错误。

MSDN有一篇文章详细介绍了一些获取伤亡链的策略:http://msdn.microsoft.com/en-us/magazine/jj891052.aspx3。根据我的理解,我有两个选择:

  • 使用System.Diagnostics.EventListener并在运行时点击性能
  • 创建一个扩展方法,并在每次await调用
  • 时使用它

有没有更好的方法来记录更多有用的详细信息?拥有伤亡链会很好,但只是获得异常来源就可以了(这是什么类型和方法)。

3 个答案:

答案 0 :(得分:3)

这两个选项都会导致运行时开销。

第三个选项(也会导致运行时开销)是使用我的AsyncDiagnostics库。我很偏爱那个(自然),但是每个选项都会引入运行时开销。

答案 1 :(得分:3)

针对.NET 4.5.1而不是4.5进行编译,通常会使用异步获得更好的异常跟踪。

答案 2 :(得分:0)

如果将程序集的PDB部署到部署DLL的同一文件夹,则异常堆栈跟踪应包含文件和行号信息。特别是,MoveNext()来电将位于您的async方法中。

如果为您的程序集启用了优化(并且它们可能适用于发布版本),则行号可能偶尔会出现不准确的情况,因此如果您仍然无法根据它告诉的行号找出问题,请记住这一点你。