Обработка исключений ASP.NET MVC Web API

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

Как говорится, я ищу способ обработки ошибок, которые происходят до того, как он достигнет API.

Рассуждение: Мы никогда не хотим возвращать ошибку YSOD и/или IIS HTML. Мы ВСЕГДА хотим попасть в специальный фильтр/обработчик исключений, чтобы мы могли корректно обрабатывать протоколирование и возвращать ответ JSON пользователю.

Как сейчас, используя Fiddler для выполнения запроса, я могу подключиться к процессу w3wp.exe и увидеть запрос, попадающий в метод Application_BeginRequest в global.asax. После этого он просто возвращает ответ 500. Он никогда не ломается в коде с исключением или не ударяет ни о каких из моих точек останова после этого. Кажется, он возвращает ошибку IIS. Мы никогда не хотим, чтобы это произошло. Нам нужна способность поймать все эти "низкоуровневые" исключения, зарегистрировать их и вернуть что-то значимое для пользователя.

Есть ли что-то, что мы можем сделать для обработки ошибок раньше, что, кажется, попадает в код ASP.NET MVC Web API?

Ответ 1

Хотя мне нравится ответ Дарина, он не работает в нашем случае, поскольку инфраструктура веб-API ASP.NET MVC подавляет/обрабатывает исключения внутренне и не перебрасывает, чтобы использовать метод Application_Error в Global.asax. Наше решение таково.

В итоге я создал пользовательский DelegatingHandler:

public class PrincipalHandler : DelegatingHandler
{
    protected const string PrincipalKey = "MS_UserPrincipal";
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        setAnonymousPrincipal();

        request = InitializeIdentity(request);

        return base.SendAsync(request, cancellationToken)
            .ContinueWith(r =>
                              {
                                  // inspect result for status code and handle accordingly
                                  return r.Result;
                              });
    }
}

Затем я вставил его в HttpConfiguration, чтобы убедиться, что это первый/последний обработчик. Способ работы обработчиков в веб-API осуществляется иерархически. Таким образом, первый обработчик, который будет попадать за запрос, будет последним обработчиком, который будет атакован. По крайней мере, это мое понимание, кто-то может исправить меня, если я ошибаюсь.

public static void ConfigureApis(HttpConfiguration config)
{
    config.MessageHandlers.Insert(0, new PrincipalHandler());
}

Используя этот подход, мы можем теперь проверять каждый результат, возвращаемый в ответ от веб-API и контроллеров. Это позволяет нам обрабатывать любые записи, которые могут возникнуть в результате чего-то, что не возвращается, как мы ожидаем. Теперь мы можем изменить содержание возвращаемого ответа, чтобы IIS не вставлял страницы ошибок HTML по умолчанию, если он видит определенные коды состояния HTTP.

Единственная проблема, с которой я столкнулся, и я надеюсь, что они изменят ее в предстоящем выпуске веб-API, заключается в том, что они не отправляют исключение в резервную копию задачи, возвращаемой из базы .SendAsync(), Таким образом, единственная информация, которую мы должны пройти, - это код статуса HTTP и стараюсь дать разумный или вероятный ответ потребителю.