поймать все необработанные исключения в ASP.NET Web Api


113

Как мне перехватить все необработанные исключения, возникающие в ASP.NET Web Api, чтобы я мог их регистрировать?

Пока я пробовал:

  • Создать и зарегистрировать ExceptionHandlingAttribute
  • Реализуйте Application_Errorметод вGlobal.asax.cs
  • Подписываться на AppDomain.CurrentDomain.UnhandledException
  • Подписываться на TaskScheduler.UnobservedTaskException

Он ExceptionHandlingAttributeуспешно обрабатывает исключения, которые возникают в методах действий контроллера и фильтрах действий, но другие исключения не обрабатываются, например:

  • Исключения, возникающие, когда IQueryableметод, возвращаемый методом действия, не может выполнить
  • Исключения, создаваемые обработчиком сообщений (т.е. HttpConfiguration.MessageHandlers)
  • Исключения, возникающие при создании экземпляра контроллера

По сути, если исключение приведет к возврату клиенту 500 Internal Server Error, я хочу, чтобы это было зарегистрировано. Реализация Application_Errorхорошо справилась с этой задачей в веб-формах и MVC - что я могу использовать в веб-API?


Вы пробовали использовать мониторинг работоспособности ASP.NET ? Просто включите его и посмотрите, не регистрируются ли ваши исключения в журнале событий.
— Джон Сондерс

Мониторинг работоспособности перехватывает исключения моего конвейера MVC, но не исключения моего конвейера Web Api.
— Джо Дейли

Спасибо - Мне потребовалось время, чтобы понять, почему я не могу зарегистрировать свои проблемы с внедрением конструктора / зависимостей, когда я думал, что у меня уже отсортировано ведение журнала WebAPI ...
— Облет

Ответы:


156

Теперь это возможно с WebAPI 2.1 (см. Что нового ):

Создайте одну или несколько реализаций IExceptionLogger. Например:

public class TraceExceptionLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        Trace.TraceError(context.ExceptionContext.Exception.ToString());
    }
}

Затем зарегистрируйтесь с помощью HttpConfiguration вашего приложения внутри обратного вызова конфигурации, например:

config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

или напрямую:

GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

7
@NeilBarnwell Да, Web API 2.1 соответствует версии 5.1.0 сборки System.Web.Http . Таким образом, вам нужна эта версия или выше, чтобы использовать решение, описанное здесь. См. Версии пакета
— nuget

2
Некоторые 500 ошибок по-прежнему не обнаруживаются, например. HttpException - удаленный хост закрыл соединение. Есть ли еще место для global.asax Application_Error для обработки ошибок вне обработки веб-API?
— Avner

11
Мне нравится, насколько подробны официальные документы на msdn, и 99% разработчиков действительно хотят только 8 строк кода для регистрации ошибок.
— Rocklan

20

Ответ Yuval предназначен для настройки ответов на необработанные исключения, обнаруженные веб-API, а не для ведения журнала, как указано на связанной странице . См. Подробности в разделе «Когда использовать» на странице. Регистратор вызывается всегда, но обработчик вызывается только тогда, когда может быть отправлен ответ. Короче говоря, используйте средство ведения журнала для ведения журнала и обработчик для настройки ответа.

Кстати, я использую сборку v5.2.3, а в ExceptionHandlerклассе нет HandleCoreметода. Я думаю, что эквивалент Handle. Однако просто подклассы ExceptionHandler(как в ответе Ювала) не работают. В моем случае я должен реализовать IExceptionHandlerследующее.

internal class OopsExceptionHandler : IExceptionHandler
{
    private readonly IExceptionHandler _innerHandler;

    public OopsExceptionHandler (IExceptionHandler innerHandler)
    {
        if (innerHandler == null)
            throw new ArgumentNullException(nameof(innerHandler));

        _innerHandler = innerHandler;
    }

    public IExceptionHandler InnerHandler
    {
        get { return _innerHandler; }
    }

    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        Handle(context);

        return Task.FromResult<object>(null);
    }

    public void Handle(ExceptionHandlerContext context)
    {
        // Create your own custom result here...
        // In dev, you might want to null out the result
        // to display the YSOD.
        // context.Result = null;
        context.Result = new InternalServerErrorResult(context.Request);
    }
}

Обратите внимание, что, в отличие от регистратора, вы регистрируете свой обработчик, заменяя обработчик по умолчанию, а не добавляя.

config.Services.Replace(typeof(IExceptionHandler),
    new OopsExceptionHandler(config.Services.GetExceptionHandler()));

1
Это отличное решение, это должно быть общепринятым решением «поймать или зарегистрировать все ошибки». Я никогда бы не понял, почему это не сработало для меня, когда я просто расширял ExceptionHandler.
— Rajiv

Отличное решение. Как только конвейер MVC был загружен для запроса, это отлично работает. IIS по-прежнему обрабатывает исключения до этого момента, в том числе при раскручивании OWIN в startup.cs. Однако в какой-то момент после завершения обработки файла startup.cs он отлично справляется со своей задачей.
— Gustyn

18

Чтобы ответить на мой собственный вопрос, это невозможно!

Обработка всех исключений, вызывающих внутренние ошибки сервера, кажется базовой возможностью, которую должен иметь веб-API, поэтому я отправил в Microsoft запрос на глобальный обработчик ошибок для веб-API :

https://aspnetwebstack.codeplex.com/workitem/1001

Если вы согласны, перейдите по этой ссылке и проголосуйте за нее!

А пока в отличной статье « Обработка исключений веб-API ASP.NET» показано несколько различных способов отлова нескольких различных категорий ошибок. Это сложнее, чем должно быть, и он не улавливает все внутренние ошибки сервера, но это лучший подход, доступный сегодня.

Обновление: глобальная обработка ошибок теперь реализована и доступна в ночных сборках! Он будет выпущен в ASP.NET MVC v5.1. Вот как это будет работать: https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling


кажется причиной использовать контроллер для вызовов ajax вместо веб-api .. границы уже размыты .. хотя, если ELMAH сможет захватить это, возможно, есть способ
— Sonic Soul

4
В Web API 2.1 добавлена ​​глобальная обработка ошибок. Подробнее см. Мой ответ.
— декабрь

10

Вы также можете создать глобальный обработчик исключений, реализовав IExceptionHandlerинтерфейс (или унаследовав ExceptionHandlerбазовый класс). Он будет последним в цепочке выполнения после всех зарегистрированных IExceptionLogger:

IExceptionHandler обрабатывает все необработанные исключения из всех контроллеров. Это последний в списке. Если возникает исключение, сначала вызывается IExceptionLogger, затем ExceptionFilters контроллера и, если все еще не обработано, реализация IExceptionHandler.

public class OopsExceptionHandler : ExceptionHandler
{
    public override void HandleCore(ExceptionHandlerContext context)
    {
        context.Result = new TextPlainErrorResult
        {
            Request = context.ExceptionContext.Request,
            Content = "Oops! Sorry! Something went wrong."        
        };
    }

    private class TextPlainErrorResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = 
                             new HttpResponseMessage(HttpStatusCode.InternalServerError);
            response.Content = new StringContent(Content);
            response.RequestMessage = Request;
            return Task.FromResult(response);
        }
    }
}

Подробнее об этом здесь .


Просто любопытно, где это прописано?
— ThunD3eR

-1

У вас могут быть существующие блоки try-catch, о которых вы не знаете.

Я думал, что мой новый global.asax.Application_Errorметод не вызывается постоянно для необработанных исключений в нашем устаревшем коде.

Затем я нашел несколько блоков try-catch в середине стека вызовов, которые вызывали Response.Write в тексте исключения. Вот и все. Вывалил текст на экран, а затем убил исключение как камень.

Итак, исключения обрабатывались, но ничего полезного не делалось. Как только я удалил эти блоки try-catch, исключения, как и ожидалось, распространялись на метод Application_Error.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.