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.