ловити всі необроблені винятки в 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.