.NET

13 ago, 2018

Fluxo de requisições e filtros no .NET Core

Publicidade

Quem trabalha com back-end de aplicações web, sabe a necessidade de ter o controle do fluxo da sua aplicação. Filtros, autorização, tokens e desserialização são algumas das necessidades mais comuns no mundo back-end.

Quando trabalhamos com .NET Core, esse controle é extremamente simplificado, pois ele foi arquitetado para ter ganchos e cada parte de uma requisição. Isso significa que podemos injetar código em diversas partes da pipeline da requisição, sem a necessidade workarounds (gambs, para os íntimos).

https://www.c-sharpcorner.com/article/working-with-filters-in-asp-net-core-mvc/

Isso abre diversas oportunidades para escrevermos código de boa qualidade, e com uma única responsabilidade. Para exemplificar o uso dos ganchos oferecidos, criei uma aplicação WebApi simples, com os seguintes filtros implementados: Resource Filter, Action Filter, Exception Filter e Result Filter; alguns exemplos para abrir o caminho, e o restante fica por sua necessidade em suas aplicações.

Filtros de Recurso

Tem a função de checar algum recurso de requisição, como cache ou valores de formulários antes do binding. Implementa a interface IResourceFilter:

    public class ResourceFilter : IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Console.WriteLine("Passando pelo Resource Filter ANTES do metodo");
        }
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Console.WriteLine("Passando pelo Resource Filter DEPOIS do metodo");
        }
    }

Ainda no Resource Filter, temos acesso ao ModelState, Session, ao objeto RouteData (onde podemos, inclusive, alterar o valor de um parâmetro de rota) e muitas outras propriedades.

Action Filter

Esse filtro é chamado logo antes e logo depois da ACTION, por isso, já temos acesso a uma instância do controller, e do ModelState também. Implementa a interface IActionFilter:

    public class ActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine("Passando pelo Action Filter ANTES do metodo");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine("Passando pelo Action Filter DEPOIS do metodo");
        }
    }

Exception Filter

Uma classe especial de filtros, chamada somente em caso da action lançar uma exceção não tratada, muito utilizada para logging e tratamento da mensagem para uma forma amigável. Implementa a interface IExceptionFilter:

    public class ExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            Console.WriteLine("Uma exceção não tratada ocorreu na action");
        }
    }

Nesse filtro, temos acesso ao ModelState também, e também temos como acessar a exceção que foi lançada.

Result Filter

Já nesse último filtro, é o passo antes de retornar a resposta para o usuário. Aqui, já temos o retorno da Action, e podemos adicionar headers, logging de sucesso e do resultado gerado, entre outras informações. Implementa a interface IResultFilter, com dois métodos: OnResultExecuting e OnResultExecuted. No primeiro é onde podemos alterar a resposta, é a nossa última chance de alterar algo antes de retornar para o usuário. No segundo método, a resposta já foi retornada, e não há mais como alterar nada.

    public class ResultFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            Console.WriteLine("Passando pelo result filter antes de retornar ao usuario.");
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
            Console.WriteLine("Passando pelo result filter apos retornar ao usuario, ja nao podemos alterar a resposta.");
        }
    }

Para adicionar esses filtros que criamos no pipeline das requisições (de forma global, para exemplificar), adicionamos esses filtros ao declarar o uso do MVC na classe Startup:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc(options => {
    options.Filters.Add(new ResourceFilter());
    options.Filters.Add(new ActionFilter());
    options.Filters.Add(new ExceptionFilter());
    options.Filters.Add(new ResultFilter());
  });
}

Rodando nossa aplicação, chamando o controller Teste (está no código fonte citado no início do artigo), temos o seguinte resultado no console:

É importante lembrar que podemos criar mais de um filtro do mesmo tipo e adicionar ao pipeline, é uma ferramenta de extrema importância para o desacoplamento de código e que poucos usam com seu total potencial. Neste exemplo simples, usamos somente o console para exemplificar, mas as possibilidades são inúmeras.

Não pare com os estudos, e busque implementar essa funcionalidade em seus projetos no trabalho ou estudo para fixar o conhecimento.

Um forte abraço, e até a próxima!

Fontes