UPDATE
Поскольку этот ответ дает решение, я не буду его редактировать, но я нашел более чистый способ решения этой проблемы. Подробнее см. мой другой ответ ...
Оригинальный ответ:
Я понял, почему метод Application_Error()
не вызывается ...
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
По умолчанию (при создании нового проекта) приложение MVC имеет некоторую логику в файле Global.asax.cs
. Эта логика используется для отображения маршрутов и регистрации фильтров. По умолчанию регистрируется только один фильтр: фильтр HandleErrorAttribute
. Когда customErrors включен (или через удаленные запросы, когда он установлен в RemoteOnly), HandleErrorAttribute указывает MVC искать представление Error и никогда не вызывает метод Application_Error()
. Я не смог найти документацию по этому вопросу, но это объяснено в этом ответе на programmers.stackexchange.com .
Чтобы метод ApplicationError () вызывался для каждого необработанного исключения, просто удалите строку, в которой регистрируется фильтр HandleErrorAttribute.
Теперь проблема: Как настроить customErrors, чтобы получить то, что вы хотите ...
В разделе customErrors по умолчанию установлено значение redirectMode="ResponseRedirect"
. Вы можете указать атрибут defaultRedirect как маршрут MVC. Я создал ErrorController, который был очень простым, и изменил мой web.config, чтобы он выглядел следующим образом ...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
Проблема с этим решением заключается в том, что он выполняет перенаправление 302 на ваши URL-адреса ошибок, а затем эти страницы отвечают кодом состояния 200. Это приводит к тому, что Google индексирует страницы ошибок, что плохо. Это также не очень соответствует спецификации HTTP. Я хотел не перенаправлять, а перезаписать исходный ответ своими пользовательскими сообщениями об ошибках.
Я пытался изменить redirectMode="ResponseRewrite"
. К сожалению, эта опция не поддерживает маршруты MVC , только статические HTML-страницы или ASPX. Сначала я пытался использовать статическую HTML-страницу, но код ответа был 200, но, по крайней мере, он не перенаправлял. Затем я получил идею от этого ответа ...
Я решил отказаться от MVC для обработки ошибок. Я создал Error.aspx
и PageNotFound.aspx
. Эти страницы были очень простыми, но у них было одно волшебство ...
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
В этом блоке указывается, что страница будет обслуживаться с правильным кодом состояния. Грубо говоря, на странице PageNotFound.aspx я использовал HttpStatusCode.NotFound
. Я изменил свой web.config, чтобы он выглядел следующим образом ...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
Всё работало отлично!
Резюме:
- Удалить строку:
filters.Add(new HandleErrorAttribute());
- Используйте метод
Application_Error()
для регистрации исключений
- Использовать customErrors с ResponseRewrite, указывая на страницы ASPX
- Сделать страницы ASPX ответственными за собственные коды статуса ответов
Есть несколько недостатков, которые я заметил с этим решением.
- Страницы ASPX не могут делиться разметкой с помощью шаблонов Razor, мне пришлось переписать стандартную разметку заголовка и нижнего колонтитула нашего сайта для согласованного внешнего вида.
- Доступ к страницам * .aspx можно получить, нажав их URL-адреса
Существуют обходные пути для этих проблем, но они меня не слишком волновали, чтобы выполнять какую-либо дополнительную работу.
Надеюсь, это поможет всем!