Как следует обрабатывать внутренние ошибки веб-API?

В нашем приложении у нас есть довольно простой набор обработчиков ведения журнала (IExceptionFilters на контроллерах MVC и API и дополнительная ловушка в Application_Error()), но есть целая категория ошибок, которые не вызывают ни одну из них. Если исключение генерируется из самого WebAPI или из чего-то, используемого внутри (например, инициализатора типа класса, созданного преобразователем зависимостей), все, что я получаю, — это ответ 500, отправляемый клиенту.

Единственный способ, который я нашел для сбора сведений об ошибке, — это использовать HttpConfiguration.IncludeErrorDetailPolicy, чтобы настроить приложение для выдачи сведений об ошибке, однако это известная плохая практика — передавать сведения об ошибке миру, поэтому я бы предпочел включить это полностью отключить или установить для него что-то условное (скажем, только локальное). Но это означает удаленное взаимодействие с сервером, на котором запущено приложение, и локальный вызов API с помощью инструмента, который может проверять ответы (например, IE или Google). Chrome), чтобы выяснить, что происходит.

Я видел здесь еще один вопрос в подобном ключе (здесь), но представленное решение (с использованием DelegatingHandler для проверки ответов) не соответствует нашим потребностям, как нам кажется. Действительно ли нет события, которое я мог бы перехватить, точки расширения, которую я мог бы использовать, или чего-то подобного, чтобы зафиксировать фактическое произошедшее исключение?

(Кроме того, я полагаю, что мог бы изменить свой IncludeErrorDetailPolicy на Always и использовать решение, представленное в другом потоке, для захвата сведений об ошибке в MessageHandler, регистрации их и ручного удаления их из ответа, отправляемого клиенту, но это был бы неприятный взлом.)

Мысли? :/


person William Scalf    schedule 18.01.2013    source источник
comment
Почему подход MessageHandler не работает для вас?   -  person Youssef Moussaoui    schedule 18.01.2013
comment
Возможно, я неправильно понимаю это, но, судя по тому, как я его читаю, единственный способ получить объект исключения, который я могу зарегистрировать, - это следовать взлому, упомянутому в конце моего вопроса, - включить включение сведений об ошибке во все ответы, затем анализирует эту информацию об ошибке, чтобы попытаться восстановить первоначально созданное исключение, а затем вручную удаляет эти сведения из ответа перед его отправкой клиенту. ... И хотя это должно работать, это звучит грубо, хрупко и подвержено потере диагностической информации и/или непреднамеренной утечке этой информации клиентам.   -  person William Scalf    schedule 18.01.2013
comment
Вы хотите сохранить диагностическую информацию и избежать утечки информации клиенту? Какие ответы вы пытаетесь отправить обратно? Почему у вас не работают значения по умолчанию? Вы получите полную диагностическую информацию на локальном компьютере для целей отладки, и никакая информация не будет передана удаленным клиентам.   -  person Youssef Moussaoui    schedule 18.01.2013
comment
Ну, да, я намерен собрать как можно больше информации на сервере и отправить минимальный ответ клиенту. Проблема в том, что для большинства ошибок мы используем встроенные в инфраструктуру механизмы для сбора сведений об ошибках для регистрации (MVC и HTTP IExceptionFilters и событие Application_Error), и это все хорошо, но, похоже, есть категория ошибок. ошибки внутри и вокруг веб-API, где такого механизма не существует - или, по крайней мере, не то, что я могу найти.   -  person William Scalf    schedule 18.01.2013


Ответы (2)


Мы отправили запрос в службу поддержки Microsoft Partner Network, и они ответили, как мне кажется, лучше.

Идея состоит в том, чтобы заменить реализацию IHttpControllerActivator платформы по умолчанию на ту, которая обертывает поведение создания контроллера по умолчанию любым дополнительным желаемым поведением.

В нашем случае это означает обертывание метода Create DefaultHttpControllerActivator конструкцией try/catch/throw и вызовом нашей службы ведения журналов. Это может не дать 100% покрытия, но большинство исключений, которые мы упускаем, связаны с созданием контроллеров, так что это должно сильно помочь.

Мне бы очень хотелось иметь возможность перехватывать метод HandleException внутри HttpControllerDispatcher, но он и приватный, и статический, так что ладно.

person William Scalf    schedule 26.02.2013
comment
+1, и просто замечание: замените также IHttpControllerSelector, IHttpActionSelector и IHttActionInvoker для полного контроля над этими внутренними ошибками. - person Konamiman; 05.11.2014

Хорошо, я понимаю, что вы пытаетесь сделать. Спасибо за разъяснения. WebAPI имеет модель, в которой ответы об ошибках не обязательно вызваны исключением. Любой может вернуть HttpResponseMessage с 400, например, без фактического создания исключения. И во многих случаях встроенные ошибки фреймворка работают одинаково, не вызывая исключения.

Теперь я думаю, что то, что вы предложили, звучит хорошо для меня. Вы можете установить для ErrorDetailPolicy значение Always и реализовать обработчик сообщений, который регистрирует ошибку и использует другой HttpError, который включает только сообщение. Вот как это может выглядеть:

public class ErrorHandlingMessageHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
        HttpError error;
        if (response.TryGetContentValue(out error))
        {
            LogError(error)
            // Use an HttpError that doesn't leak internal information
            (response.Content as ObjectContent).Value = new HttpError(error.Message);
        }

        return response;
    }
}

Обратите внимание, что мы не очищаем существующую ошибку. Мы создаем новый, чтобы снизить риск утечки информации. Сообщение всегда должно быть безопасным для отправки обратно. Это не распространяется на отправку обратно состояния модели, но если вам это нужно, вы всегда можете скопировать его в новую ошибку.

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

person Youssef Moussaoui    schedule 18.01.2013