ATUALIZAÇÃO
Como essa resposta fornece uma solução, não a editarei, mas encontrei uma maneira muito mais limpa de resolver esse problema. Veja minha outra resposta para obter detalhes ...
Resposta original:
Eu descobri por que o Application_Error()
método não está sendo chamado ...
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 padrão (quando um novo projeto é gerado), um aplicativo MVC possui alguma lógica no Global.asax.cs
arquivo. Essa lógica é usada para mapear rotas e registrar filtros. Por padrão, ele registra apenas um filtro: um HandleErrorAttribute
filtro. Quando customErrors está ativado (ou por meio de solicitações remotas quando está definido como RemoteOnly), o HandleErrorAttribute diz ao MVC para procurar uma visualização de Erro e nunca chama o Application_Error()
método. Não consegui encontrar documentação disso, mas está explicada nesta resposta em programmers.stackexchange.com .
Para obter o método ApplicationError () chamado para todas as exceções não tratadas, remova a linha que registra o filtro HandleErrorAttribute.
Agora, o problema é: Como configurar os customErrors para obter o que você deseja ...
A seção customErrors é padronizada como redirectMode="ResponseRedirect"
. Você também pode especificar o atributo defaultRedirect como uma rota MVC. Eu criei um ErrorController que era muito simples e alterei meu web.config para ficar assim ...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
O problema com esta solução é que ele faz um redirecionamento 302 para os URLs de erro e, em seguida, essas páginas respondem com um código de status 200. Isso leva o Google a indexar as páginas de erro, o que é ruim. Também não é muito compatível com a especificação HTTP. O que eu queria fazer não era redirecionar e substituir a resposta original com minhas visualizações de erro personalizadas.
Eu tentei mudar redirectMode="ResponseRewrite"
. Infelizmente, esta opção não suporta rotas MVC , apenas páginas HTML estáticas ou ASPX. Tentei usar uma página HTML estática no início, mas o código de resposta ainda era 200, mas pelo menos não foi redirecionado. Então eu tive uma idéia desta resposta ...
Decidi desistir do MVC pelo tratamento de erros. Eu criei um Error.aspx
e um PageNotFound.aspx
. Essas páginas eram muito simples, mas tinham um pedaço de mágica ...
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
Este bloco informa a página a ser veiculada com o código de status correto. De grosso modo, na página PageNotFound.aspx, eu usei HttpStatusCode.NotFound
. Mudei meu web.config para ficar assim ...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
Tudo funcionou perfeitamente!
Resumo:
- Remova a linha:
filters.Add(new HandleErrorAttribute());
- Use o
Application_Error()
método para registrar exceções
- Use customErrors com um ResponseRewrite, apontando para páginas ASPX
- Responsabilize as páginas ASPX por seus próprios códigos de status de resposta
Há algumas desvantagens que notei com esta solução.
- As páginas ASPX não podem compartilhar nenhuma marcação com os modelos do Razor, tive que reescrever a marcação padrão do cabeçalho e rodapé do nosso site para obter uma aparência consistente.
- As páginas * .aspx podem ser acessadas diretamente pressionando seus URLs
Existem soluções alternativas para esses problemas, mas eu não estava preocupado o suficiente com eles para fazer qualquer trabalho extra.
Eu espero que isso ajude a todos!