ОНОВЛЕННЯ
Оскільки ця відповідь дає рішення, я не буду її редагувати, але я знайшов набагато більш чистий спосіб вирішення цієї проблеми. Дивіться іншу відповідь для деталей ...
Оригінальна відповідь:
Я зрозумів, чому 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
фільтр. Коли користувальницькі помилки включені (або за допомогою віддалених запитів, коли для нього встановлено RemoteOnly), HandleErrorAttribute повідомляє MVC шукати перегляд помилок, і він ніколи не викликає 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-адреси
Для цих проблем існують робочі місця, але я не був достатньо стурбований ними, щоб виконувати зайву роботу.
Я сподіваюся, що це допомагає всім!