ACTUALIZACIÓN
Dado que esta respuesta proporciona una solución, no la editaré, pero he encontrado una forma mucho más limpia de resolver este problema. Vea mi otra respuesta para más detalles ...
Respuesta original:
descubrí por qué Application_Error()
no se invoca el método ...
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
Por defecto (cuando se genera un nuevo proyecto), una aplicación MVC tiene cierta lógica en el Global.asax.cs
archivo. Esta lógica se utiliza para mapear rutas y registrar filtros. Por defecto, solo registra un filtro: un HandleErrorAttribute
filtro. Cuando customErrors están activados (o mediante solicitudes remotas cuando se establece en RemoteOnly), HandleErrorAttribute le dice a MVC que busque una vista de Error y nunca llama al Application_Error()
método. No pude encontrar documentación de esto, pero se explica en esta respuesta en programmers.stackexchange.com .
Para obtener el método ApplicationError () para cada excepción no controlada, simplemente elimine la línea que registra el filtro HandleErrorAttribute.
Ahora el problema es: cómo configurar CustomErrors para obtener lo que desea ...
La sección customErrors está predeterminada en redirectMode="ResponseRedirect"
. También puede especificar que el atributo defaultRedirect sea una ruta MVC. Creé un ErrorController que era muy simple y cambié mi web.config para que se viera así ...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
El problema con esta solución es que hace una redirección 302 a sus URL de error y luego esas páginas responden con un código de estado 200. Esto lleva a que Google indexe las páginas de error, lo cual es malo. Tampoco es muy conforme a la especificación HTTP. Lo que quería hacer no era redirigir y sobrescribir la respuesta original con mis vistas de error personalizadas.
Traté de cambiar redirectMode="ResponseRewrite"
. Desafortunadamente, esta opción no admite rutas MVC , solo páginas HTML estáticas o ASPX. Al principio intenté usar una página HTML estática, pero el código de respuesta seguía siendo 200 pero, al menos, no se redirigió. Entonces tuve una idea de esta respuesta ...
Decidí renunciar a MVC para el manejo de errores. Creé un Error.aspx
y a PageNotFound.aspx
. Estas páginas eran muy simples pero tenían una pieza de magia ...
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
Este bloque le dice a la página que se sirva con el código de estado correcto. En general, en la página PageNotFound.aspx, usé en su HttpStatusCode.NotFound
lugar. Cambié mi web.config para que se vea así ...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
¡Todo funcionó a la perfección!
Resumen:
- Eliminar la línea:
filters.Add(new HandleErrorAttribute());
- Use el
Application_Error()
método para registrar excepciones
- Use customErrors con ResponseRewrite, apuntando a páginas ASPX
- Haga que las páginas ASPX sean responsables de sus propios códigos de estado de respuesta
Hay un par de inconvenientes que he notado con esta solución.
- Las páginas ASPX no pueden compartir ningún marcado con las plantillas Razor, tuve que reescribir el marcado estándar de encabezado y pie de página de nuestro sitio web para una apariencia consistente.
- Se puede acceder directamente a las páginas * .aspx presionando sus URL
Hay soluciones para estos problemas, pero no me preocuparon lo suficiente como para hacer un trabajo extra.
¡Espero que esto ayude a todos!