Entendendo e Aplicando Filtros no ASP.NET MVC (HandleError)

Entendendo e Aplicando Filtros no ASP.NET MVC (HandleError)

O que são filtros

Filtros são recursos que existem no ASP.NET MVC que nos permitem injetar comportamentos a nível de Controller, Action e em nível Global.

E nesse post vou mostrar e abordar de forma prática como trabalhar com filtros.

Inicialmente vamos trabalhar com o filtro HandlerError, que é o filtro para tratamento de exceção padrão no framework.

O registro dos filtros são feitos no Global.asax.cs :

using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace FiltrosNoASP.NETMVC
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application\_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

No método estático RegisterGlobalFilters da classe FilterConfig.cs, é onde adicionamos nossos filtros globais, ou seja, os filtros que são aplicados aqui são replicados para todos os controllers e actions de nosso projeto.

using System.Web.Mvc;

namespace FiltrosNoASP.NETMVC
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }
}

No caso acima está sendo aplicado o filtro HandlerErrorAttribute que é o filtro para tratamentos de erros a nível de todo o projeto.
E como funciona o tratamento do HandlerErrorAttribute? O HandlerErrorAttribute é habilitado através da tag customErrors dentro da tag system.web no Web.config:

<customErrors mode="On">

  </customErrors>

Quando habilitamos o mode On, automaticamente erros do tipo 500 são roteados para Views/Shared/Error.cshtml.

É possível mudar para uma view de erro diferente, bastar estanciar o HandlerErrorAttribute apontando para uma view customizada, é preciso que essa view esteja dentro de Views/Shared/ViewCustomizada.cshtml.

filters.Add(new HandleErrorAttribute() { View = "ViewCustomizada"})

Veja o exemplo onde simulo uma exceção na action Index do Controller Home:

public class HomeController : Controller
    {
        public ActionResult Index()
        {
            throw new Exception("Erro na Index");
            return View();
        }
    }

Retorno:

1
Se a tag estivesse desabilitada o retorno seria esse:

2

Ok, e se eu comentar o filtro global HandlerErrorAttribute, o que acontece? Acontece um erro em tempo de execução, pois ele não consegue rotear a informação, veja:

3
Para saber detalhes do erro, podemos editar as informações na View de erro, nesse caso vamos alterar a view de erro a Erro.cshtml, exemplo:

@model System.Web.Mvc.HandleErrorInfo
@{
 ViewBag.Title = "Error";
}

<h2>Controller: @Model.ControllerName</h2>
<h2> Action: @Model.ActionName</h2>

<h1 class="text-danger">Mensagem: @Model.Exception.Message</h1>
<h2 class="text-danger">Pilha do Erro: @Model.Exception.StackTrace</h2>

Retorno:

4
Filtros em nível de Controller e Action:

Para trabalhar com HandlerError a nível de controller, precisamos decorar o nosso controller, exemplo:

namespace FiltrosNoASP.NETMVC.Controllers
{
    \[HandleError(View = "ViewErroController")\] //Redireciona para View ViewErroController
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            throw new Exception("Erro na Index");
            return View();
        }
    }
}

Agora vamos aplicar em nível de Action:

namespace FiltrosNoASP.NETMVC.Controllers
{
    \[HandleError(View= "ViewErroController")\]
    public class TesteController : Controller
    {
        \[HandleError(View = "ViewErroAction")\]
        public ActionResult Index()
        {
            throw new Exception("Erro ao executar operação");
            return View();
        }
    }
}

Hierarquicamente o tratamento de exceção utilizando filtros vem do mais genérico para mais especializado, no exemplo acima o erro acontece na Action Index, a pagina de erro customizada a ser exibida será a ViewErroAction, caso contrario a ViewErroController seria exibida, depois disso seria a nível global.

Também é possível customizar o tipo de exceção, exemplo InvalidOperationException:

namespace FiltrosNoASP.NETMVC.Controllers
{
    \[HandleError(View = "ViewErroController")\]
    public class TesteErroPorTipoDeExcecaoController : Controller
    {
        \[HandleError(View = "ViewErroActionPorTipo",ExceptionType = typeof(InvalidOperationException))\]
        public ActionResult Index()
        {
            throw new InvalidOperationException("Erro operação Invalida");
            return View();
        }
    }
}

Para fazer o download dos fontes clique aqui

Bom pessoal, é isso, nesse primeiro post deu para ter uma ideia de como funcionam os filtros de exceção com o HandleError.