поймать всех необработанных исключений в веб ASP.NET API-интерфейс


как поймать все необработанные исключения, которые происходят в ASP.NET веб-Api, чтобы я мог их регистрировать?

до сих пор я пробовал:

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

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

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

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

5 104

5 ответов:

Теперь это возможно с 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());

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

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

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

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

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

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

ответ 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()));

вы также можете создать глобальный обработчик исключений по реализации 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);
        }
    }
}

об этом здесь.

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

затем я нашел несколько блоков try-catch в середине стека вызовов, который вызвал Response.Напишите на текст исключения. Вот и все. Сбросил текст на экран, а затем убил исключение stone dead.