2016-05-04 2 views
1

У меня есть простое синхронное действие в контроллере, который генерирует исключение, например так:ExceptionFilter трассировки стека в синхронном сценарии действий

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

Я также имею ExceptionFilterAttribute ухватить исключений, которые возникают при применении

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

Все работает нормально, так как я занимаюсь исключением в MyExceptionFilterAttribute. Проблема заключается в трассировке стека. Вот как это выглядит:

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

Так мой вопрос: Как я могу получить «реальную» трассировку стеки (что будет указывать на метод в контроллере, где случилось исключение)?

В целом, потому что, очевидно, есть что-то, чего я не понимаю, откуда происходит асинхронный переход из этого сценария? Является ли веб-api автоматически создавать асинхронную задачу при попадании на метод контроллера?

Я использую Web API v2.0 (packages v5.0.0) и не могу обновить до более поздних версий (сложная история).

Подробнее: Я побежал в this question поэтому я попытался унаследовать от ActionFilterAttribute вместо ExceptionFilterAttribute но трассировки стека уже был похож на один выше, когда ActionFilterAttribute получал удар.

ответ

1

Если вам не нужно обновлять пакеты веб-API, то лучшим вариантом является, вероятно, избежать использования ActionFilters для обработки исключений вообще.

Лучше (и глобальный) подход должен был бы создать 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; 
    } 
} 

А внутри WebApiConfig.cs (предполагающей config Ваш HttpConfiguration объект):

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

Если вы хотите зарегистрировать исключение (и не обрабатывать его каким-либо образом), то вы можете реализовать ExceptionLogger аналогичным образом:

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

И снова:

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

Спасибо Федерико, я не знал об интерфейсе IExceptionHandler. IExceptionLogger будет еще лучше, но, к сожалению, он появился в 5.1.2 (Web API 2.1). Тем не менее, это решение в основном работает для меня. Есть ли у вас какие-либо идеи, где, например, асинхронный материал появляется в моем примере? –

+0

Я считаю, что это происходит потому, что каждый фильтр действий реализует интерфейс 'IActionFilter', который [только объявляет' ExecuteActionFilterAsync'] (http://sourcebrowser.io/Browse/ASP-NET-MVC/aspnetwebstack/src/System.Web.Http /Filters/IActionFilter.cs#11). 'ActionFilterAttribute' сам [вызывает синхронные методы внутри асинхронных] (http://sourcebrowser.io/Browse/ASP-NET-MVC/aspnetwebstack/src/System.Web.Http/Filters/ActionFilterAttribute.cs) и, следовательно, все обернуто внутри 'Задачи'. –

+0

Yup, имеет большой смысл. Большое вам спасибо за вашу помощь! –

Смежные вопросы