Mais acessados

quarta-feira, 19 de setembro de 2012

ASP.NET MVC – Tratando erros HTTP e Exceções

Nesse artigo mostrarei um exemplo prático e simples de como exibir mensagens amigáveis caso aconteça um erro HTTP ou alguma exceção em sua aplicação.

Tratando Erros HTTP



Passo 1 – Criando um NotFoundActionResult


Criaremos nosso próprio ActionResult que retornará nossos erros. Abaixo segue a implementação para o Erro 404, mas nada impede que implemente para outros =).
public class NotFoundActionResult : ActionResult
{
 private string _viewName;
 public NotFoundActionResult()
 {

 }
 public NotFoundActionResult(string viewName)
 {
  _viewName = viewName;
 }
 public override void ExecuteResult(ControllerContext context)
 {
  context.HttpContext.Response.StatusCode = 404;
  context.HttpContext.Response.TrySkipIisCustomErrors = true;

  new ViewResult { ViewName = string.IsNullOrEmpty(_viewName) ? "Error" : _viewName}.ExecuteResult(context);
 }
}
No método ExecuteResult, indicamos o StatusCode como 404 e setamos TrySkipIisCustomErrors para true para que o IIS não lance suas páginas de exceção.

Passo 2 – Criando nosso ErrorController


 public class ErrorController : Controller
    {
        public ActionResult NotFound()
        {
            return new NotFoundActionResult("NotFound");
        }
    }
Veja que passei como paramentro o nome da minha View para o NotFoundActionResult que acabamos de criar. </>

Passo 3 – Registrando Filtro



Para que nossas exceções sejam capturadas precisando registrar HandleErrorAttribute na lista de filtros do aplicativo. Dessa forma qualquer exception lançada será capturada.
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
  filters.Add(new HandleErrorAttribute());
 }

Passo 4 – Criando uma View personalizada


Criaremos uma View tipada para HandleErrorInfo, assim caso aconteça uma exception no meio do caminho a mensagem será exibida, caso contrátio ela exibirá a mensagem de página não encontrada. Uma view amigável é muito melhor que a tela amarela da morte lançada pelo IIS =P, principalmente quando é exibida pra o usuário final.
@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = "Ops!";
}

Erro.

@if (@Model != null) {

@Model.Exception

} else {

Ops! 404 (Page Not Found)! A página não foi encontrada, provavelmente o endereço foi movido ou removido. Contate seu administrador de redes.

}

Passo 5 – Adicionando rotas


Precisamos registrar duas rotas: uma para tratar os erros para Actions ou Controllers que não existem (NotFound) e outra para tratar qualquer rota que fuja àquelas que foram definidas para nossa aplicação (NotFound-catchall).
public static void RegisterRoutes(RouteCollection routes)
{
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 routes.MapRoute(
  name: "NotFound",
  url: "NotFound/{action}/{id}",
  defaults: new
  {
   controller = "Error",
   action = "NotFound",
   id = UrlParameter.Optional
  }
 );
 routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new
  {
   id = RouteParameter.Optional
  }
 );
 routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}",
  defaults: new { controller = "Home", action = "Index"}
 );
 routes.MapRoute(
    name: "NotFound-catchall",
    url: "{*all}",
    defaults: new { controller = "Error", action = "NotFound" }
    );
}
Não se esqueça que a ordem em que as rotas são registradas é a ordem de precedência para validação, logo a útima rota deve ser a genérica (NotFound-catchall) que trata qualquer url inválida.

Tratando Exceções



Passo 1 – Criando uma View personalizada


Mais uma vez criaremos uma view tipada para HandleErrorInfo, e usaremos a mensagem de Erro e o Stack Trace capturados. Note que validamos se a requisicão é local para que o usuário final não veja o erro lançado, mas sim uma mensagem amigável.
@model System.Web.Mvc.HandleErrorInfo

@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Erro

Erro

Erro ao executar a requisição

@{ if (Request.IsLocal) { if (@Model != null && @Model.Exception != null) {

Exception: @Model.Exception.Message

Stack Trace: @Model.Exception.StackTrace

} } else {

O erro foi reportado ao Administrador.

} }

Finalizando


É necessário ativar o customErrors para que nossos erros sejam redirecionados. Assim adicione ao arquivo as seguintes linhas:

 
      
 
Note que adicionei o erro 404 porque nosso ActionResult personalizado trata erros 404. Para cada Erro, você deve incluir uma linha no arquivo, caso deseje tratálos em páginas separadas.
O código fonte desse exemplo está disponível aqui.