简体   繁体   中英

ExceptionFilter stack trace in synchronous action scenario

I have a simple synchronous action in a Controller that throws an exception like so :

[RoutePrefix("")]
public class MyController : ApiController
{
    [Route("")]
    public HttpResponseMessage Get()
    {
        throw new Exception("whatever");
        return Request.CreateResponse(HttpStatusCode.OK, "response");
    }
}

I also have an ExceptionFilterAttribute to get a hold of exceptions that occur in the application

public class MyExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext actionContext)
    {
        var ex = actionContext.Exception;
        // Log ex, etc.
    }
}

Everything works fine in that I do get a hold of the exception in MyExceptionFilterAttribute . The problem is the stack trace. Here is what it looks like :

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()"

So my question : How do I get the "real" stack trace (that would point to the method in the controller where the exception occured) ?

More generally, because clearly there is something I don't understand, where is the async coming from in this scenario ? Does the web api automatically create an async task when it hits a controller method ?

I am using Web API v2.0 ( packages v5.0.0 ) and cannot upgrade to more recent versions (complicated story).

More info : I ran into this question so I tried inheriting from ActionFilterAttribute instead of ExceptionFilterAttribute but the stack trace already looked like the above one when the ActionFilterAttribute was getting hit.

If you are forced to not upgrade Web API packages, then you best option is probably to avoid using ActionFilters for handling exceptions at all.

A better (and global) approach would be to create an ExceptionHandler to replace the default implementation inside the Web API configuration:

public class MyExceptionHandler : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {
        var ex = context.Exception;

        //log exception, do stuff

        context.Result = new InternalServerErrorResult(context.Request);
    }

    public override bool ShouldHandle(ExceptionHandlerContext context)
    {
        bool shouldHandle;

        //logic to check if you should handle the exception or not

        return shouldHandle;
    }
}

And inside WebApiConfig.cs (assuming config is your HttpConfiguration object):

config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());

If you, instead, only want to log the exception (and not handling it in some way), then you could implement an ExceptionLogger in a similar way:

public class MyExceptionLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        MyLogger.Log(LogLevel.Error, context.Exception, "some message");
    }
}

And again:

config.Services.Replace(typeof(IExceptionLogger), new MyExceptionLogger());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM