Настраиваемое сообщение об ошибке в ASP.NET MVC при возникновении исключения в HttpModule - PullRequest
3 голосов
/ 23 мая 2011

Я использую ASP.NET MVC. Я перехватываю любое необработанное исключение на OnException в BaseController, чтобы правильно показать красивое сообщение.

Однако у меня есть проект модуля Http в том же решении. Модуль может выдать InvalidOperationException, если пользователь сделал неправильный запрос. Я использую интегрированный режим IIS7, и все было настроено правильно. Я новичок в жизни IIS и исключение модуля Http.

Googling нашел способ обработки исключений только с помощью HttpMethod, который отличается от этого случая.

Вопрос в том, было ли выброшено исключение в модуле, MVC будет выполняться или нет? Если это так, почему он не собирается OnException? а как получить исключение в MVC как у метода Action?

Редактировать: Основываясь на ответе @nickvane о жизненном цикле приложения, я пытаюсь объяснить ситуацию лучше. Я думаю, что любой HttpModule, даже созданный мной, может вызвать любое исключение. Я хочу, чтобы это исключение было обработано моим MVC, который находится в UrlRoutingModule. Я думаю о:

  • Заказ HttpModule
  • Необработанное исключение останавливает модуль, и следующий модуль никогда не будет работать?
  • Как обрабатывать исключение в веб-приложении MVC (UrlRoutingModule), если его просто добавить в другой модуль HttpModule, выполненный до или после UrlRoutingModule.
  • Могу ли я получить исключение в другом модуле, используя context.AllErrors или context.Error? Но я не смог получить ошибку.

Единственный способ, который я нашел на планете, - это изменить выбрасываемое исключение на Server.Transfer(), но как насчет других модулей, которые не являются моими, все равно выдает исключение, и я хочу его перехватить.

Подумайте об этом: я создаю MVC Restful API, который ДОЛЖЕН возвращать JSON. Я могу правильно обработать любое исключение в приложении MVC, используя OnException, чтобы любое необработанное исключение возвращало что-то вроде {"Ошибка": "Сообщение об ошибке здесь."}. Теперь у меня есть HttpModule, который может выдать ошибку. Модуль не касается API и JSON, он просто выдает исключение. Затем я пытаюсь перехватить это исключение в MVC для возврата в формате JSON.

1 Ответ

4 голосов
/ 23 мая 2011

Время жизни контроллера или httpmodule очень разное.Эта ссылка показывает жизненный цикл приложения asp.net:

http://msdn.microsoft.com/en-us/library/bb470252.aspx

Хотя он не предназначен специально для asp.net mvc, инфраструктура mvc подключается к этому жизненному циклу и следует по этому конвейеру.:

http://ajaxus.net/wp-content/uploads/2010/01/asp_net_mvc_poster.pdf

С http://www.asp.net/mvc/tutorials/understanding-the-asp-net-mvc-execution-process-vb

Запросы к веб-приложению на основе ASP.NET MVC сначала проходят через объект UrlRoutingModule, который являетсяМодуль HTTP.Этот модуль анализирует запрос и выполняет выбор маршрута.Объект UrlRoutingModule выбирает первый объект маршрута, соответствующий текущему запросу.(Объект маршрута - это класс, который реализует RouteBase и, как правило, является экземпляром класса Route.) Если ни один из маршрутов не совпадает, объект UrlRoutingModule ничего не делает и позволяет запросу вернуться к обычной обработке запросов ASP.NET или IIS.

Из выбранного объекта Route объект UrlRoutingModule получает объект IRouteHandler, связанный с объектом Route.Как правило, в приложении MVC это будет экземпляр MvcRouteHandler.Экземпляр IRouteHandler создает объект IHttpHandler и передает ему объект IHttpContext.По умолчанию экземпляр IHttpHandler для MVC является объектом MvcHandler.Затем объект MvcHandler выбирает контроллер, который в конечном итоге будет обрабатывать запрос.

HttpModule подключается к жизненному циклу приложения и может выполнять код до того, как будет создан экземпляр контроллера или после его удаления, в зависимости от того, в какомсобытия, которые он обрабатывает из жизненного цикла приложения.Поэтому он не может использовать обработку исключений контроллера.

Если вы хотите правильно обработать исключение в модуле http, я думаю, что у вас есть 2 варианта:

  1. Когда вы ловитеИсключение: вы можете изменить ответ на запрос.Вы можете вставить ошибку div или заменить весь ответ сообщением об ошибке или просто зарегистрировать исключение.В этом случае запрос будет следовать за остальной частью конвейера.
  2. Или вы можете выбросить исключение и обработать его в методе global.asax Application_Error.В этом сценарии контроллер не будет выполнен.

Если HttpModule выдает допустимое исключение, я бы выбрал вариант 2. Вы можете выдать собственное исключение и обработать его по-другому в глобальном.asax, даже возвращая ответ HTTP (400 неверных запросов).

Обновление

Если в HttpModule возникает исключение, оно будет перехвачено методом Application_Error.Я попробовал следующий фрагмент кода, который работает, хотя кажется, что он неправильный:

protected void Application_Error()
    {
        var ex = Server.GetLastError(); // get the last exception that was made
        if (ex == null) return; // if there is no exception, just continue
        Response.ClearContent();
        Response.Write("{'error':'" + ex.Message + "'}");
        Response.ContentType = "application/json";
        Response.Flush(); // flush the content to the client
        Response.Close(); // and close the connection so that no other content can be written to the response
        Server.ClearError(); // clear the error so that asp.net does not use the custom error page. If we don't close the response and clear the error, the request will still be handled in the rest of the pipeline.
    }
...