ОБНОВЛЕНИЕ
Поскольку этот ответ предоставляет решение, я не буду его редактировать, но я нашел более чистый способ решения этой проблемы. Подробнее см. Мой другой ответ ...
Исходный ответ:
я понял, почему 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-адреса.
Для этих проблем есть обходные пути, но они меня не слишком беспокоили, чтобы делать дополнительную работу.
Надеюсь, это поможет всем!