简体   繁体   English

同步动作场景中的 ExceptionFilter 堆栈跟踪

[英]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我还有一个 ExceptionFilterAttribute 来获取应用程序中发生的异常

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 .一切正常,因为我确实掌握了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 ?当 web api 遇到控制器方法时,它是否会自动创建一个异步任务?

I am using Web API v2.0 ( packages v5.0.0 ) and cannot upgrade to more recent versions (complicated story).我正在使用 Web API v2.0(包 v5.0.0 )并且无法升级到更新的版本(复杂的故事)。

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.更多信息:我遇到了这个问题,所以我尝试从 ActionFilterAttribute 而不是 ExceptionFilterAttribute 继承,但是当ActionFilterAttribute被击中时,堆栈跟踪已经看起来像上面的那样。

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.如果您被迫不升级 Web API 包,那么您最好的选择可能是完全避免使用ActionFilters来处理异常。

A better (and global) approach would be to create an ExceptionHandler to replace the default implementation inside the Web API configuration:更好(和全局)的方法是创建一个ExceptionHandler来替换 Web API 配置中的默认实现:

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):WebApiConfig.cs (假设config是您的HttpConfiguration对象):

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:相反,如果您只想记录异常(而不是以某种方式处理它),那么您可以以类似的方式实现ExceptionLogger

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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