How to get correct stack trace for exceptions in Web API 2 async actions?

前端 未结 3 1041
陌清茗
陌清茗 2021-02-13 04:53

I have a simple API controller method

public async Task GetByDate(DateTime date, string user = null)
{
    throw new InvalidOperationExce         


        
相关标签:
3条回答
  • 2021-02-13 05:23

    So after I asked the question I got the right motivation to properly dig through Web API code to find the issue. It seems that the culprit is ActionFilterAttribute.CallOnActionExecutedAsync method that does something like this (paraphrased, not the actual code):

    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;
    

    So it happens that the first filter actually gets the correct stack trace. But then it just goes and rethrows the exception, thus losing the original stack trace.

    This made me realize that instead of deriving from ExceptionFilterAttribute, I need to derive from ActionFilterAttribute since the former are always called last. Unfortunately I also need to make sure my exception filter runs first but that is not built-in Web API (see this question for a correct solution for this).

    My quick solution was to make sure all filters I have in the application (I only have a few) derive from my custom exception filter (and call base.OnActionExecuted()) thus every single filter will actually check for the exception and perform something like this:

    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;
    }
    

    With this workaround I got the correct stack traces both to the log and to the user if error details are turned on.

    0 讨论(0)
  • 2021-02-13 05:29

    This has been fixed in WebApi 2.1 (assembly version 5.1.1)

    Follow these instructions to upgrade to the latest version: https://www.nuget.org/packages/Microsoft.AspNet.WebApi

    0 讨论(0)
  • 2021-02-13 05:40

    I believe stack traces are improved on .NET 4.5.1 when running on Windows 8.1 / Server 2012 R2.

    Alternatively, I do have an "Async Diagnostics" NuGet package that you can install into your project. Then add this line:

    [assembly: AsyncDiagnosticAspect]
    

    And you can use the ToAsyncDiagnosticString extension method on the Exception type. ToAsyncDiagnosticString includes all the information from ToString and then appends a "logical stack". More documentation (and the source) on GitHub.

    Note that there is no support for partial trust and this works best in Debug builds.

    0 讨论(0)
提交回复
热议问题