问题
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.
回答1:
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());
来源:https://stackoverflow.com/questions/37039046/exceptionfilter-stack-trace-in-synchronous-action-scenario