AKTUALIZACJA
Ponieważ ta odpowiedź dostarcza rozwiązania, nie będę jej edytować, ale znalazłem znacznie czystszy sposób rozwiązania tego problemu. Zobacz moją drugą odpowiedź po szczegóły ...
Oryginalna odpowiedź:
Dowiedziałem się, dlaczego Application_Error()
metoda nie jest wywoływana ...
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
Domyślnie (podczas generowania nowego projektu) aplikacja MVC ma pewną logikę w Global.asax.cs
pliku. Ta logika jest używana do mapowania tras i rejestrowania filtrów. Domyślnie rejestruje tylko jeden filtr: HandleErrorAttribute
filtr. Gdy customErrors są włączone (lub przez żądania zdalne, gdy jest ustawiona na RemoteOnly), HandleErrorAttribute informuje MVC, aby szukał widoku błędu i nigdy nie wywołuje Application_Error()
metody. Nie mogłem znaleźć dokumentacji na ten temat, ale jest to wyjaśnione w tej odpowiedzi na programmers.stackexchange.com .
Aby uzyskać metodę ApplicationError () wywoływaną dla każdego nieobsługiwanego wyjątku, po prostu usuń wiersz, który rejestruje filtr HandleErrorAttribute.
Teraz problem jest taki: jak skonfigurować customErrors, aby uzyskać to, czego chcesz ...
Sekcja customErrors jest domyślnie ustawiona na redirectMode="ResponseRedirect"
. Możesz również określić atrybut defaultRedirect jako trasę MVC. Stworzyłem ErrorController, który był bardzo prosty i zmieniłem mój web.config, aby wyglądał tak ...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
Problem z tym rozwiązaniem polega na tym, że przekierowuje ono 302 do adresów URL błędów, a następnie te strony odpowiadają kodem stanu 200. Prowadzi to do indeksowania przez Google stron błędów, co jest złe. Nie jest też bardzo zgodny ze specyfikacją HTTP. Nie chciałem przekierować i zastąpić oryginalnej odpowiedzi moimi niestandardowymi widokami błędów.
Próbowałem się zmienić redirectMode="ResponseRewrite"
. Niestety ta opcja nie obsługuje tras MVC , tylko statyczne strony HTML lub ASPX. Na początku próbowałem użyć statycznej strony HTML, ale kod odpowiedzi wciąż miał 200, ale przynajmniej nie przekierowywał. Wtedy wpadłem na pomysł z tej odpowiedzi ...
Postanowiłem zrezygnować z MVC do obsługi błędów. Stworzyłem Error.aspx
i PageNotFound.aspx
. Te strony były bardzo proste, ale miały jeden kawałek magii ...
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
Ten blok informuje, że strona ma być obsługiwana z poprawnym kodem stanu. Z grubsza, na stronie PageNotFound.aspx użyłem HttpStatusCode.NotFound
zamiast tego. Zmieniłem plik web.config, aby wyglądał tak ...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
Wszystko działało idealnie!
Podsumowanie:
- Usuń linię:
filters.Add(new HandleErrorAttribute());
- Użyj
Application_Error()
metody do rejestrowania wyjątków
- Użyj customErrors z ResponseRewrite, wskazując na strony ASPX
- Spraw, aby strony ASPX były odpowiedzialne za własne kody stanu odpowiedzi
W przypadku tego rozwiązania zauważyłem kilka wad.
- Strony ASPX nie mogą udostępniać żadnych znaczników z szablonami Razor, musiałem przepisać standardowe znaczniki nagłówka i stopki naszej witryny, aby uzyskać spójny wygląd i styl.
- Dostęp do stron * .aspx można uzyskać bezpośrednio, klikając ich adresy URL
Istnieją sposoby obejścia tych problemów, ale nie przejmowałem się nimi na tyle, aby wykonać jakąkolwiek dodatkową pracę.
Mam nadzieję, że to pomoże wszystkim!