Моя цель - создать обработку ошибок в приложении, которая обрабатывает все управляемые ошибки, а не только связанные с MVC. Поэтому я не использую шаблон HandleErrorAttribute, потому что он предназначен только для ошибок MVC, а не для других управляемых ошибок.
В моем Global.asax у меня есть:
protected void Application_Error()
{
string displayError = ConfigurationManager.AppSettings["DisplayError"];
NameValueCollection serverVariables;
int loop1, loop2;
StringBuilder serverVariableKeys = new StringBuilder();
Exception exception = Server.GetLastError();
HttpException httpException = exception as HttpException;
if (HttpContext.Current != null)
{
// loop through and get server vars
}
if (exception != null)
// Log Error
// Redirect to Error page if set to basic mode
if (!string.IsNullOrWhiteSpace(displayError) && displayError.ToLower() == "basic")
{
Response.Clear();
Server.ClearError(); // needed for redirect to work
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new Controllers.ErrorController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
}
У меня есть ErrorController
, который имеет General
, Http403
и Http404
Действия. У меня есть мнения, соответствующие каждому действию.
В моем web.config у меня есть:
<system.web>
<!-- removed bits to reduce space -->
<customErrors mode="On" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules >
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
<remove name="Session"/>
<add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition=""/>
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<httpErrors errorMode="Detailed" />
</system.webServer>
Это работает для многих сценариев, связанных с управляемым кодом, но когда IIS берет на себя, например, плохой статический вызов файла (example.com/BadFileName.gif), он возвращает ошибку из IIS, которая раскрывает данные сервера, такие как путь к локальному файлу, Это происходит из-за следующей строки в файле web.config:
<httpErrors errorMode="Detailed" />
Но когда я устанавливаю значение errorMode для других значений, таких как Custom, или просто удаляю строку, моя пользовательская обработка ошибок перестает работать, и сообщения об ошибках IIS по умолчанию возвращаются для всех, включая ошибки управляемого кода.
Я пробовал несколько вещей, чтобы добраться до пользовательских ошибок, чтобы работать без этого параметра без везения, в том числе:
CustomError
- mode="Off"
CustomError
для перенаправления на мои контроллерыhttpErrors
для перенаправления на мои контроллерыКогда я перехожу к отладке, я вижу вызов контроллера, но в конце IIS вместо этого отправляет ответ. Ведение журнала ошибок правильно вызвано Application_Error, поэтому код позволяет приложению обрабатывать его до определенной точки.
Сведения о приложении:
Есть ли способ не использовать <httpErrors errorMode="Detailed" />
и сделать эту работу?
Причина, по которой вы видите поведение, вероятно, что ваш обработчик Application_Error
правильно вызывается (и вызывает ваш контроллер), но затем IIS перехватывает ошибку 500 и отображает собственную страницу ошибок. (хотя также возможно, что ваш обработчик Application_Error
сам выбрасывает Exception
, что вы хотите исключить)
Поскольку вы хотите обрабатывать все ошибки (например, упомянутую статическую ошибку файла), вы, вероятно, не сможете использовать ASP.NET или ASP.NET MVC для первоначального обнаружения ошибок. Не все ошибки поступают из вашего приложения!
Самое лучшее, что нужно сделать, это ориентироваться на обработку ошибок IIS 7.5 столько, сколько вы можете, а не пытаться слишком рано вовлечь себя в себя. Пусть IIS сделает первоначальное обнаружение ошибок для вас, и это намного проще.
Попробуйте поместить следующее в свой web.config
, заменив существующий httpErrors
node: -
<httpErrors errorMode="Custom" existingResponse="Replace">
<clear />
<error statusCode="400" responseMode="ExecuteURL" path="/Error" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/Forbidden" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
Удалите customErrors
node полностью. Это не нужно.
Помните и убедитесь, что ваш контроллер ошибок задает правильный код состояния: -
public ActionResult Forbidden()
{
Response.StatusCode = 403;
return this.View();
}
После этого вы можете отбросить все, кроме выхода из вашего обработчика Application_Error
, хотя я думаю, что вам лучше всего создать свой собственный HttpModule
; установка runAllManagedModulesForAllRequests
в модулях node в вашем web.config
поможет вам уловить ошибки, которые в противном случае проскальзывают.
У меня есть эта настройка (хотя я лично использую elmah для ведения журнала), работающую на предварительном просмотре веб-сайтов Azure, и она захватывает все, за исключением, очевидно, любых ошибок, возникающих из-за невозможности разобрать web.config
.
Я положил полный рабочий пример использования httpErrors для пользовательских страниц ошибок на github. Вы также можете видеть его вживую на лазурных веб-сайтах.
Если вы хотите обработать это в своем приложении, вы можете написать собственный обработчик или использовать атрибут HandleError здесь - хороший пример одного из способов подходить к этому вместо того, чтобы использовать IIS в качестве костыля. так как не все хост-провайдеры IIS разрешают этот тип настройки на уровне сервера, а IMO - плохой подход, поскольку он создает дополнительную конфигурацию во время развертывания.