ASP.NET
Core MVC - Tratamento de erros - I
![]() |
Neste artigo vamos rever os conceitos envolvidos no tratamento de erros em aplicações ASP.NET Core MVC. |
A ASP.NET Core MVC é um framework usado para desenvolver aplicativos da web com interfaces de usuário interativas. Nesse tipo de aplicação, o tratamento de erros geralmente envolve a exibição de mensagens de erro na interface do usuário para informar o usuário final sobre o problema
As principais diferenças no tratamento de erros em aplicações ASP.NET Core MVC incluem:
[HandleError]
,
para lidar com exceções lançadas dentro dos controladores. Esses filtros
podem redirecionar para uma página de erro personalizada ou exibir uma
visualização de erro adequada.A seguir temos o roteiro que vamos seguir para discutir o tratamento de erros em aplicações MVC:
1- Tratamento de exceções no ambiente de
desenvolvimento
Abordagem : UseDeveloperExceptionPage
2 - Tratamento de Exceções em Ambiente de Produção
Abordagem 1:
UseExceptionHandler
1: Página do
Manipulador de Exceções(Exception Handler Page)
2:
Manipulador de Exceções Lambda(Exception Handler Lambda)
Abordagem 2:
UseStatusCodePages
1:
UseStatusCodePages, e com string de formato e com Lambda
2:
UseStatusCodePagesWithRedirects
3:
UseStatusCodePagesWithReExecute
Abordagem 3: Filtro
de exceção
a-
Local
b-
Global
1- Tratamento de exceções no ambiente de desenvolvimento
Vamos criar uma aplicação ASP.NET usando o template
ASP.NET Core Web App(Model-View-Controller) chamada
MvcTrataErros onde teremos a seguinte estrutura após a criação do
projeto:
Ao analisar o projeto criado veremos na classe Program o código abaixo:
... if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } ... |
Este trecho de código registra um manipulador de erros que é chamado quando um erro ocorre na aplicação se o ambiente da aplicação não for o ambiente de desenvolvimento. Neste caso o manipulador de erros redireciona aciona o método Action Error do controlador Home que vai invocar a view Error.cshtml existente na pasta Shared.
O método Action Error do controller possui este código:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } |
Note que estamo usando a anotação
[
Essa é uma anotação (atributo) que configura o cache da resposta HTTP para a
Action Error()
. Nesse caso, Duration = 0
indica que a
resposta não deve ser armazenada em cache,
ResponseCacheLocation.None
especifica que não deve haver um
cache intermediário entre o servidor e o cliente, e
NoStore = true
indica que o cache do navegador também deve ser
desabilitado para essa resposta.
O segundo bloco do código,
app.UseHsts()
,
habilita o Strict Transport Security (HSTS) para a
aplicação. O HSTS é um recurso de segurança que força os navegadores a se
comunicarem com a aplicação apenas usando o protocolo HTTPS.
Durante o desenvolvimento, a ASP.NET Core configura automaticamente a classe
DeveloperExceptionPageMiddleware
como
um dos primeiros middlewares na pipeline de processamento de request. Esse
middleware captura exceções não tratadas e exibe informações detalhadas sobre o
erro, incluindo uma página de exceção com rastreamento de pilha e outras
informações úteis para depuração.
O uso do DeveloperExceptionPageMiddleware
no ambiente de desenvolvimento ajuda os desenvolvedores a identificar e corrigir
problemas rapidamente, fornecendo uma visão clara dos erros que ocorrem durante
a execução da aplicação.
É importante observar que o
DeveloperExceptionPageMiddleware
não deve ser usado em um
ambiente de produção, pois pode expor informações sensíveis sobre a
aplicação e apresentar possíveis riscos de segurança. No ambiente de produção, é
recomendado configurar um tratamento de erros apropriado, como um middleware de
tratamento de erros personalizado ou uma página de erro personalizada, que
forneça uma resposta mais controlada e amigável aos usuários finais.
A página de exceção do desenvolvedor mostra rastreamentos de pilha detalhados para erros do servidor e usa a classe DeveloperExceptionPageMiddleware para capturar exceções síncronas e assíncronas do pipeline HTTP e gerar respostas de erro.
Para mostrar como esta classe atua vamos alterar o código do método Action Index controlador HomeController conforme abaixo:
public
IActionResult Index(int?
id = null) { if (id.HasValue) { if (id == 1) { throw new FileNotFoundException("Arquivo não encontrado, lançou a exceção na view Index.cshtml"); } else if (id == 2) { return StatusCode(500); } } return View(); } |
A seguir vamos alterar a view Index.cshtml da pasta Views usando o seguinte código:
@{ ViewData["Title"] = "Home Page"; } <br /> <div class="text-left"> <p> <a href="/PaginaNaoExiste"> Request para um endpoint que não existe. Dispara um Error 404 </a>. </p> <p><a href="/home/index/1">Dispara uma exceção</a>. </p> <p> <a href="/home/index/2">Retorna um erro internod do servidor : Error 500</a>. </p> </div> |
Executando o projeto teremos a seguinte pagina inicial:
Ao clicar no primeiro link teremos o erro 404 pois a pagina /PaginaNaoExiste não existe mesmo:
O código de status 404 pode ser causado por uma variedade de fatores, incluindo:
Se você receber o código de status 404, a primeira coisa que você deve fazer é verificar o URL do recurso. Se a URL estiver correta, você pode tentar novamente mais tarde. Se a URL estiver incorreta, você pode tentar corrigi-lo. Se você ainda não conseguir acessar o recurso, você pode entrar em contato com o suporte técnico para obter ajuda.
Ao clicar no terceiro link teremos o retorno do código de status (StatusCode) 500 indicando um erro interno de servidor:
Ele é retornado quando o servidor não consegue processar uma solicitação devido a um erro inesperado.
O código de status 500 pode ser causado por uma variedade de fatores, incluindo:
Se você receber o código de status 500, a primeira coisa que você deve fazer é verificar os logs do servidor. Os logs podem fornecer informações sobre a causa do erro. Se você não conseguir identificar a causa do erro nos logs, você pode entrar em contato com o suporte do servidor para obter ajuda.
Aqui estão algumas dicas para ajudar a evitar o código de status 500:
Agora clicando no link do meio teremos a exibição da seguinte página:
Esta é a pagina de exceção do desenvolvedor emitida pela classe DeveloperExceptionPageMiddleware que inclui as seguintes informações sobre a exceção e a solicitação :
Podemos assim exibir todas essas informações relacionadas com o request e a exceção gerada. Como exemplo a seguir temos os Headers:
Por este motivo esta abordagem deve ser usada apenas no ambiente de desenvolvimento.
2 - Tratamento de Exceções em Ambiente de Produção
Ao executar a sua aplicação no ambiente de produção já vimos que a classe UseExceptionHandler será usada para realizar o tratamento de erros conforme configuração feita na classe Program:
... if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } ... |
Agora como saber em qual embiente estamos executando a nossa aplicação MVC ?
O ASP.NET Core configura o comportamento do aplicativo com base no ambiente de tempo de execução determinado no arquivo launchSettings.json presente na pasta Properties do projeto.
Para o nosso projeto ele possui o seguinte código:
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:56239", "sslPort": 44359 } }, "profiles": { "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "http://localhost:5167", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "https://localhost:7230;http://localhost:5167", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } |
O objetivo principal do
launchSettings.json
é fornecer uma maneira conveniente de configurar e gerenciar as
diferentes configurações de ambiente e opções de execução para a aplicação. Ele
é usado principalmente pelo Visual Studio e pelo Visual Studio Code durante o
desenvolvimento, mas também pode ser usado em outros ambientes de
desenvolvimento integrados (IDEs) ou ao executar a aplicação manualmente por
linha de comando.
Através do launchSettings.json
,
você pode definir perfis de execução, cada um representando uma configuração
específica para a execução da aplicação. Cada perfil pode conter várias
propriedades, como o ambiente de execução, a porta em que a aplicação será
executada, a URL base, configurações de depuração, entre outras.
Alguns perfis comuns definidos no launchSettings.json
são:
IIS Express
: Perfil para
executar a aplicação usando o servidor web IIS Express.ProjectName
: Perfil padrão
para executar a aplicação usando o Kestrel (servidor web incorporado do
ASP.NET Core).Docker
: Perfil para executar a
aplicação em um contêiner Docker.O arquivo launchSettings.json
também contém as seguintes
propriedades:
commandName
: O nome do comando
para iniciar a aplicação. O valor padrão é dotnet
.workingDirectory
: O diretório
de trabalho para a aplicação. O valor padrão é o diretório do projeto.launchBrowser
: Se a aplicação
deve ser lançada no navegador. O valor padrão é true
.browser
: O navegador para
lançar a aplicação. Os valores possíveis são chrome
,
firefox
e edge
. Observe que em environmentVariables temos a definição da variável de ambiente ASPNETCORE_ENVIRONMENT que é usada para especificar o ambiente de execução em uma aplicação ASP.NET Core. Essa variável permite que você defina o ambiente em que a aplicação deve ser executada, como :
Ao definir a variável de ambiente
ASPNETCORE_ENVIRONMENT
, a aplicação ASP.NET Core usa essa
configuração para determinar qual conjunto de configurações aplicar. Por padrão,
se a variável não for definida, o ambiente é considerado "Production".
Vamos alterar o valor desta variável para 'Production' no arquivo launchSettings.json :
"ASPNETCORE_ENVIRONMENT": "Production"Agora o tratamento de erros será feito pela classe UseExceptionHandler e vai acionar o método Action Error do controlador Home que vai invocar a view Error.cshtml existente na pasta Shared.
Executando novamente o projeto e clicando no link do meio para gerar uma exceção teremos o seguinte resultado:
Assim vemos que este middleware de manipulação de exceção :
Observe que não temos aqui a exibição de detalhes dos erros no ambiente de produção. Cabe a você definir como vai notificar os usuários quando da ocorrência de uma exceção.
Para ilustrar podemos redefinir o código definido na classe Program para :
... if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/error"); } } ... |
A seguir vamos configurar uma Action no controlador HomeController para responder a rota /error:
[Route("/error")] public IActionResult HandleError() => Problem(); |
Desta forma a Action HandleError envia um payload compatível com a RFC 7807 para o cliente.
O payload Problem contém as seguintes propriedades:
type
: O tipo do problema.title
: O título do problema.
Este é uma descrição curta do problema.status
: O código de status
HTTP do problema.detail
: A descrição detalhada
do problema. instance
: O URI da instância
específica do problema. Este recurso é uma maneira útil de fornecer informações adicionais sobre erros que são retornados em respostas HTTP. Ele pode ajudar os usuários a entender e solucionar o problema.
Lembrando que você não deve usar no método Action do manipulador de erro atributos HTTP, como HttpGet pois os verbos explícitos impedem que alguns requests cheguem ao método Action.
E estamos conversados.
"E houve também entre eles contenda, sobre qual deles parecia ser o maior.
E ele lhes disse: Os reis dos gentios dominam sobre eles, e os que têm
autoridade sobre eles são chamados benfeitores. Mas não sereis vós assim; antes
o maior entre vós seja como o menor; e quem governa como quem serve."
Lucas 22:24-26
Referências: