ловити всі необроблені винятки в 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 внутрішніх помилок сервера, я хочу, щоб він був зареєстрований. Виконавши Application_Errorцю роботу добре в веб-формах та MVC - що я можу використовувати в Web Api?


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

Моніторинг здоров'я фіксує мої винятки з конвеєра MVC, але не є моїми винятками з конвеєра Web Api.
— Джо Дейлі

Дякую - мені знадобилося певний час, щоб зрозуміти, чому я не можу зареєструвати проблеми введення конструктора / залежності, де я вважав, що вже впорядковано ведення журналу WebAPI ...
— Overflew

Відповіді:


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 . Тож вам потрібна ця версія або вище, щоб використовувати описане тут рішення. Дивіться нові версії пакету
— декати

2
Певні 500 помилок все ще не вловлюються цим, наприклад. HttpException - віддалений хост закрив з'єднання. Чи є ще місце для global.asax Application_Error для обробки помилок поза обробкою веб-api?
— Авнер

11
Мені подобається, наскільки детально написано офіційне doco на msdn, і що дійсно хочуть 99% розробників - це лише 8 рядків коду для входу в систему помилок.
— Роклан

20

Відповідь Юваля полягає в налаштуванні відповідей на необроблені винятки, викладені веб-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.
— Раджив

Прекрасне рішення. Після завантаження трубопроводу MVC для запиту це чудово працює. IIS досі обробляє винятки, в тому числі під час активації OWIN у startup.cs. Однак у якийсь момент після віджимання закінчується обробка startup.cs, вона справляє свою роботу чудово.
— Густин

18

Щоб відповісти на моє власне питання, це неможливо!

Поводження з усіма винятками, які спричиняють внутрішні помилки сервера, схоже, повинні мати веб-API базової можливості, тому я подав запит у Microsoft на обробник глобальних помилок для веб-API :

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

Якщо ви згодні, перейдіть за цим посиланням і проголосуйте за нього!

Тим часом, у чудовій статті ASP.NET Web API «Обробка виключень» показано кілька різних способів виявити кілька різних категорій помилок. Це складніше, ніж повинно бути, і він не вловлює всі помилки між серверами, але це найкращий підхід, доступний сьогодні.

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


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

4
У веб-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

Можливо, у вас є існуючі блоки, які ви не знаєте.

Я подумав, що мій новий global.asax.Application_Errorметод не вимагається послідовного виклику необроблених винятків у нашому застарілому коді.

Тоді я знайшов кілька блоків спробувати-уловлення посеред стека викликів, який називав Response.Write у тексті винятку. Це було все. Викинувши текст на екран, тоді вбив камінь винятку мертвим.

Тож оброблялися винятки, але обробка не робила нічого корисного. Після того, як я видалив ці тестові блоки, винятки, розповсюджені методом Application_Error, як очікувалося.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.