Filtros no ASP.NET CoreFilters in ASP.NET Core

Por Rick Anderson, Tom Dykstra e Steve SmithBy Rick Anderson, Tom Dykstra, and Steve Smith

Os Filtros no ASP.NET Core MVC permitem executar código antes ou depois de determinados estágios do pipeline de processamento de solicitações.Filters in ASP.NET Core MVC allow you to run code before or after specific stages in the request processing pipeline.

Importante

Este tópico não se aplica a Páginas Razor.This topic does not apply to Razor Pages. O ASP.NET Core 2.1 e posterior dão suporte a IPageFilter e IAsyncPageFilter nas Páginas do Razor.ASP.NET Core 2.1 and later supports IPageFilter and IAsyncPageFilter for Razor Pages. Para obter mais informações, confira Métodos de filtro para Páginas Razor.For more information, see Filter methods for Razor Pages.

O filtros internos lidam com tarefas como:Built-in filters handle tasks such as:

  • Autorização (impedir o acesso a recursos aos quais o usuário não está autorizado).Authorization (preventing access to resources a user isn't authorized for).
  • Garantir que todas as solicitações usem HTTPS.Ensuring that all requests use HTTPS.
  • Cache de resposta (causar um curto-circuito do pipeline de solicitação para retornar uma resposta armazenada em cache).Response caching (short-circuiting the request pipeline to return a cached response).

É possível criar filtros personalizados para lidar com interesses paralelos.Custom filters can be created to handle cross-cutting concerns. Os filtros podem evitar a duplicação de código entre as ações.Filters can avoid duplicating code across actions. Por exemplo, um filtro de exceção de tratamento de erro poderia consolidar o tratamento de erro.For example, an error handling exception filter could consolidate error handling.

Exibir ou baixar amostra do GitHub.View or download sample from GitHub.

Como os filtros funcionam?How do filters work?

Os filtros são executados dentro do pipeline de invocação de ações do MVC, às vezes chamado de pipeline de filtros.Filters run within the MVC action invocation pipeline, sometimes referred to as the filter pipeline. O pipeline de filtros é executado após o MVC selecionar a ação a ser executada.The filter pipeline runs after MVC selects the action to execute.

A solicitação é processada por meio de Outro Middleware, do Middleware de Roteamento, da Seleção de Ação e do Pipeline de Invocação de Ações do MVC.

Tipos de filtroFilter types

Cada tipo de filtro é executado em um estágio diferente no pipeline de filtros.Each filter type is executed at a different stage in the filter pipeline.

  • Filtros de autorização são executados primeiro e são usados para determinar se o usuário atual tem autorização para a solicitação atual.Authorization filters run first and are used to determine whether the current user is authorized for the current request. Eles podem fazer um curto-circuito do pipeline quando uma solicitação não é autorizada.They can short-circuit the pipeline if a request is unauthorized.

  • Filtros de recurso são os primeiros a lidar com uma solicitação após a autorização.Resource filters are the first to handle a request after authorization. Eles podem executar código antes do restante do pipeline de filtros e após o restante do pipeline ser concluído.They can run code before the rest of the filter pipeline, and after the rest of the pipeline has completed. Esses filtros são úteis para implementar o cache ou para, de alguma forma, fazer o curto-circuito do pipeline de filtros por motivos de desempenho.They're useful to implement caching or otherwise short-circuit the filter pipeline for performance reasons. Eles são executados antes do model binding, portanto, podem influenciar o model binding.They run before model binding, so they can influence model binding.

  • Filtros de ação podem executar código imediatamente antes e depois de um método de ação individual ser chamado.Action filters can run code immediately before and after an individual action method is called. Eles podem ser usados para manipular os argumentos passados para uma ação, bem como o resultado da ação.They can be used to manipulate the arguments passed into an action and the result returned from the action.

  • Filtros de exceção são usados para aplicar políticas globais para exceções sem tratamento que ocorrem antes que qualquer coisa tenha sido gravada no corpo da resposta.Exception filters are used to apply global policies to unhandled exceptions that occur before anything has been written to the response body.

  • Filtros de resposta podem executar código imediatamente antes e depois da execução de resultados de ações individuais.Result filters can run code immediately before and after the execution of individual action results. Eles são executados somente quando o método de ação é executado com êxito.They run only when the action method has executed successfully. Eles são úteis para a lógica que precisa envolver a execução da exibição ou do formatador.They are useful for logic that must surround view or formatter execution.

O diagrama a seguir mostra como esses tipos de filtro interagem no pipeline de filtros.The following diagram shows how these filter types interact in the filter pipeline.

A solicitação é processada por meio de Filtros de autorização, Filtros de recurso, Model binding, Filtros de ação, Execução de ação e Conversão do resultado de ação, Filtros de exceção, Filtros de resultado e Execução de resultado.

ImplementaçãoImplementation

Os filtros dão suporte a implementações síncronas e assíncronas por meio de diferentes definições de interface.Filters support both synchronous and asynchronous implementations through different interface definitions.

Filtros síncronos que podem executar código antes e depois do estágio do pipeline definem os métodos OnStageExecuting e OnStageExecuted.Synchronous filters that can run code both before and after their pipeline stage define OnStageExecuting and OnStageExecuted methods. Por exemplo, OnActionExecuting é chamado antes que o método de ação seja chamado e OnActionExecuted é chamado após o método de ação retornar.For example, OnActionExecuting is called before the action method is called, and OnActionExecuted is called after the action method returns.

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
        }
    }
}

Filtros assíncronos definem um único método OnStageExecutionAsync.Asynchronous filters define a single OnStageExecutionAsync method. Esse método usa um delegado FilterTypeExecutionDelegate, que executa o estágio de pipeline do filtro.This method takes a FilterTypeExecutionDelegate delegate which executes the filter's pipeline stage. Por exemplo, ActionExecutionDelegate chama o método de ação ou o próximo filtro de ação, e você pode executar código antes e depois de chamá-lo.For example, ActionExecutionDelegate calls the action method or next action filter, and you can execute code before and after you call it.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            // do something before the action executes
            var resultContext = await next();
            // do something after the action executes; resultContext.Result will be set
        }
    }
}

É possível implementar interfaces para vários estágios do filtro em uma única classe.You can implement interfaces for multiple filter stages in a single class. Por exemplo, a classe ActionFilterAttribute implementa IActionFilter, IResultFilter e seus equivalentes assíncronos.For example, the ActionFilterAttribute class implements IActionFilter, IResultFilter, and their async equivalents.

Observação

Implemente ou a versão assíncrona ou a versão síncrona de uma interface de filtro, não ambas.Implement either the synchronous or the async version of a filter interface, not both. Primeiro, a estrutura verifica se o filtro implementa a interface assíncrona e, se for esse o caso, a chama.The framework checks first to see if the filter implements the async interface, and if so, it calls that. Caso contrário, ela chama os métodos da interface síncrona.If not, it calls the synchronous interface's method(s). Se você implementasse as duas interfaces em uma classe, somente o método assíncrono seria chamado.If you were to implement both interfaces on one class, only the async method would be called. Ao usar classes abstratas como ActionFilterAttribute, você substituiria apenas os métodos síncronos ou o método assíncrono para cada tipo de filtro.When using abstract classes like ActionFilterAttribute you would override only the synchronous methods or the async method for each filter type.

IFilterFactoryIFilterFactory

IFilterFactory implementa IFilterMetadata.IFilterFactory implements IFilterMetadata. Portanto, uma instância IFilterFactory pode ser usada como uma instância IFilterMetadata em qualquer parte do pipeline de filtro.Therefore, an IFilterFactory instance can be used as an IFilterMetadata instance anywhere in the filter pipeline. Quando se prepara para invocar o filtro, a estrutura tenta convertê-lo em um IFilterFactory.When the framework prepares to invoke the filter, it attempts to cast it to an IFilterFactory. Se essa conversão for bem-sucedida, o método CreateInstance será chamado para criar a instância IFilterMetadata que será invocada.If that cast succeeds, the CreateInstance method is called to create the IFilterMetadata instance that will be invoked. Isso fornece um design flexível, porque o pipeline de filtro preciso não precisa ser definido explicitamente quando o aplicativo é iniciado.This provides a flexible design, since the precise filter pipeline doesn't need to be set explicitly when the app starts.

Você pode implementar IFilterFactory em suas próprias implementações de atributo como outra abordagem à criação de filtros:You can implement IFilterFactory on your own attribute implementations as another approach to creating filters:

public class AddHeaderWithFactoryAttribute : Attribute, IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new InternalAddHeaderFilter();
    }

    private class InternalAddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "Internal", new string[] { "Header Added" });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Atributos de filtro internosBuilt-in filter attributes

A estrutura inclui filtros internos baseados em atributos que você pode organizar em subclasses e personalizar.The framework includes built-in attribute-based filters that you can subclass and customize. Por exemplo, o seguinte Filtro de resultado adiciona um cabeçalho à resposta.For example, the following Result filter adds a header to the response.

using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class AddHeaderAttribute : ResultFilterAttribute
    {
        private readonly string _name;
        private readonly string _value;

        public AddHeaderAttribute(string name, string value)
        {
            _name = name;
            _value = value;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                _name, new string[] { _value });
            base.OnResultExecuting(context);
        }
    }
}

Os atributos permitem que os filtros aceitem argumentos, conforme mostrado no exemplo acima.Attributes allow filters to accept arguments, as shown in the example above. Você adicionaria esse atributo a um método de ação ou controlador e especificaria o nome e o valor do cabeçalho HTTP:You would add this attribute to a controller or action method and specify the name and value of the HTTP header:

[AddHeader("Author", "Steve Smith @ardalis")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header should be set.");
    }

O resultado da ação Index é mostrado abaixo – os cabeçalhos de resposta são exibidos na parte inferior direita.The result of the Index action is shown below - the response headers are displayed on the bottom right.

Ferramentas para Desenvolvedores do Microsoft Edge mostrando cabeçalhos de resposta, inclusive o autor Steve Smith

Várias interfaces de filtro têm atributos correspondentes que podem ser usados como classes base para implementações personalizadas.Several of the filter interfaces have corresponding attributes that can be used as base classes for custom implementations.

Atributos de filtro:Filter attributes:

  • ActionFilterAttribute
  • ExceptionFilterAttribute
  • ResultFilterAttribute
  • FormatFilterAttribute
  • ServiceFilterAttribute
  • TypeFilterAttribute

TypeFilterAttribute e ServiceFilterAttribute são explicados posteriormente neste artigo.TypeFilterAttribute and ServiceFilterAttribute are explained later in this article.

Escopos e ordem de execução dos filtrosFilter scopes and order of execution

Um filtro pode ser adicionado ao pipeline com um de três escopos.A filter can be added to the pipeline at one of three scopes. É possível adicionar um filtro a um método de ação específico ou a uma classe de controlador usando um atributo.You can add a filter to a particular action method or to a controller class by using an attribute. Ou você pode registrar um filtro globalmente para todos os controladores e ações.Or you can register a filter globally for all controllers and actions. Os filtros são adicionados globalmente quando são adicionados à coleção MvcOptions.Filters em ConfigureServices:Filters are added globally by adding it to the MvcOptions.Filters collection in ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", 
            "Result filter added to MvcOptions.Filters")); // an instance
        options.Filters.Add(typeof(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}

Ordem padrão de execuçãoDefault order of execution

Quando há vários filtros para um determinado estágio do pipeline, o escopo determina a ordem padrão de execução dos filtros.When there are multiple filters for a particular stage of the pipeline, scope determines the default order of filter execution. Filtros globais circundam filtros de classe, que, por sua vez, circundam filtros de método.Global filters surround class filters, which in turn surround method filters. Isso é, às vezes, chamado de aninhamento de "bonecas russas", pois cada aumento de escopo é encapsulado em torno do escopo anterior, como uma matriosca.This is sometimes referred to as "Russian doll" nesting, as each increase in scope is wrapped around the previous scope, like a nesting doll. Normalmente, você obtém o comportamento de substituição desejado sem precisar determinar uma ordem explicitamente.You generally get the desired overriding behavior without having to explicitly determine ordering.

Como resultado desse aninhamento, o código posterior dos filtros é executado na ordem inversa do código anterior.As a result of this nesting, the after code of filters runs in the reverse order of the before code. A sequência é semelhante a esta:The sequence looks like this:

  • O código anterior de filtros aplicados globalmenteThe before code of filters applied globally
    • O código anterior de filtros aplicados a controladoresThe before code of filters applied to controllers
      • O código anterior de filtros aplicados a métodos de açãoThe before code of filters applied to action methods
      • O código posterior de filtros aplicados a métodos de açãoThe after code of filters applied to action methods
    • O código posterior de filtros aplicados a controladoresThe after code of filters applied to controllers
  • O código posterior de filtros aplicados globalmenteThe after code of filters applied globally

Este é um exemplo que ilustra a ordem na qual métodos de filtro são chamados para filtros de ação síncronos.Here's an example that illustrates the order in which filter methods are called for synchronous Action filters.

SequênciaSequence Escopo do filtroFilter scope Método do filtroFilter method
11 GlobalGlobal OnActionExecuting
22 ControladorController OnActionExecuting
33 MétodoMethod OnActionExecuting
44 MétodoMethod OnActionExecuted
55 ControladorController OnActionExecuted
66 GlobalGlobal OnActionExecuted

Esta sequência mostra:This sequence shows:

  • O filtro de método está aninhado no filtro de controlador.The method filter is nested within the controller filter.
  • O filtro de controlador está aninhado no filtro global.The controller filter is nested within the global filter.

Para colocar de outra forma, se você estiver dentro do método OnStageExecutionAsync de um filtro assíncrono, todos os filtros com escopo mais estreito serão executados enquanto seu código estiver na pilha.To put it another way, if you're inside an async filter's OnStageExecutionAsync method, all of the filters with a tighter scope run while your code is on the stack.

Observação

Cada controlador que herda da classe base Controller inclui os métodos OnActionExecuting e OnActionExecuted.Every controller that inherits from the Controller base class includes OnActionExecuting and OnActionExecuted methods. Esses métodos encapsulam os filtros que são executados para uma determinada ação: OnActionExecuting é chamado antes de qualquer um dos filtros e OnActionExecuted é chamado após todos os filtros.These methods wrap the filters that run for a given action: OnActionExecuting is called before any of the filters, and OnActionExecuted is called after all of the filters.

Substituindo a ordem padrãoOverriding the default order

É possível substituir a sequência padrão de execução implementando IOrderedFilter.You can override the default sequence of execution by implementing IOrderedFilter. Essa interface expõe uma propriedade Order que tem precedência sobre o escopo para determinar a ordem de execução.This interface exposes an Order property that takes precedence over scope to determine the order of execution. Um filtro com um valor mais baixo de Order terá seu código anterior executado antes que um filtro com um valor mais alto de Order.A filter with a lower Order value will have its before code executed before that of a filter with a higher value of Order. Um filtro com um valor mais baixo de Order terá seu código posterior executado depois que um filtro com um valor mais alto de Order.A filter with a lower Order value will have its after code executed after that of a filter with a higher Order value. Você pode definir a propriedade Order usando um parâmetro de construtor:You can set the Order property by using a constructor parameter:

[MyFilter(Name = "Controller Level Attribute", Order=1)]

Se você tiver os mesmos três filtros de ação mostrados no exemplo anterior, mas definir a propriedade Order dos filtros de controlador e global como 1 e 2 respectivamente, a ordem de execução será invertida.If you have the same 3 Action filters shown in the preceding example but set the Order property of the controller and global filters to 1 and 2 respectively, the order of execution would be reversed.

SequênciaSequence Escopo do filtroFilter scope Propriedade OrderOrder property Método do filtroFilter method
11 MétodoMethod 00 OnActionExecuting
22 ControladorController 11 OnActionExecuting
33 GlobalGlobal 22 OnActionExecuting
44 GlobalGlobal 22 OnActionExecuted
55 ControladorController 11 OnActionExecuted
66 MétodoMethod 00 OnActionExecuted

A propriedade Order tem precedência sobre o escopo ao determinar a ordem na qual os filtros serão executados.The Order property trumps scope when determining the order in which filters will run. Os filtros são classificados primeiro pela ordem e o escopo é usado para desempatar.Filters are sorted first by order, then scope is used to break ties. Todos os filtros internos implementam IOrderedFilter e definem o valor de Order padrão como 0.All of the built-in filters implement IOrderedFilter and set the default Order value to 0. Para os filtros internos, o escopo determina a ordem, a menos que você defina Order com um valor diferente de zero.For built-in filters, scope determines order unless you set Order to a non-zero value.

Cancelamento e curto-circuitoCancellation and short circuiting

Você pode fazer um curto-circuito no pipeline de filtros a qualquer momento, definindo a propriedade Result no parâmetro context fornecido ao método do filtro.You can short-circuit the filter pipeline at any point by setting the Result property on the context parameter provided to the filter method. Por exemplo, o filtro de recurso a seguir impede que o resto do pipeline seja executado.For instance, the following Resource filter prevents the rest of the pipeline from executing.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ShortCircuitingResourceFilterAttribute : Attribute,
            IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.Result = new ContentResult()
            {
                Content = "Resource unavailable - header should not be set"
            };
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
}

No código a seguir, os filtros ShortCircuitingResourceFilter e AddHeader têm como destino o método de ação SomeResource.In the following code, both the ShortCircuitingResourceFilter and the AddHeader filter target the SomeResource action method. O ShortCircuitingResourceFilter:The ShortCircuitingResourceFilter:

  • É executado primeiro, porque ele é um filtro de recurso e AddHeader é um filtro de ação.Runs first, because it's a Resource Filter and AddHeader is an Action Filter.
  • Causa um curto-circuito no restante do pipeline.Short-circuits the rest of the pipeline.

Portanto, o filtro AddHeader nunca é executado para a ação SomeResource.Therefore the AddHeader filter never runs for the SomeResource action. Esse comportamento seria o mesmo se os dois filtros fossem aplicados no nível do método de ação, desde que ShortCircuitingResourceFilter fosse executado primeiro.This behavior would be the same if both filters were applied at the action method level, provided the ShortCircuitingResourceFilter ran first. O ShortCircuitingResourceFilter é executado primeiro, devido ao seu tipo de filtro ou pelo uso explícito da propriedade Order.The ShortCircuitingResourceFilter runs first because of its filter type, or by explicit use of Order property.

[AddHeader("Author", "Steve Smith @ardalis")]
public class SampleController : Controller
{
    public IActionResult Index()
    {
        return Content("Examine the headers using developer tools.");
    }

    [ShortCircuitingResourceFilter]
    public IActionResult SomeResource()
    {
        return Content("Successful access to resource - header should be set.");
    }

Injeção de dependênciaDependency injection

Filtros podem ser adicionados por tipo ou por instância.Filters can be added by type or by instance. Se você adicionar uma instância, ela será usada para cada solicitação.If you add an instance, that instance will be used for every request. Se você adicionar um tipo, ele será ativado pelo tipo, o que significa que uma instância será criada para cada solicitação e as dependências de construtor serão populadas pela DI (injeção de dependência).If you add a type, it will be type-activated, meaning an instance will be created for each request and any constructor dependencies will be populated by dependency injection (DI). Adicionar um filtro por tipo é equivalente a filters.Add(new TypeFilterAttribute(typeof(MyFilter))).Adding a filter by type is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).

Filtros que são implementados como atributos e adicionados diretamente a classes de controlador ou métodos de ação não podem ter dependências de construtor fornecidas pela DI (injeção de dependência).Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by dependency injection (DI). Isso ocorre porque os atributos precisam ter os parâmetros de construtor fornecidos quando eles são aplicados.This is because attributes must have their constructor parameters supplied where they're applied. Essa é uma limitação do funcionamento dos atributos.This is a limitation of how attributes work.

Se seus filtros tiverem dependências que você precisa acessar da DI, há várias abordagens com suporte.If your filters have dependencies that you need to access from DI, there are several supported approaches. É possível aplicar o filtro a um método de ação ou classe usando uma das opções a seguir:You can apply your filter to a class or action method using one of the following:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • IFilterFactory implementado em seu atributoIFilterFactory implemented on your attribute

Observação

Uma dependência que talvez você queira obter da DI é um agente.One dependency you might want to get from DI is a logger. No entanto, evite criar e usar filtros apenas para fins de registro em log, pois é possível que os recursos de registro em log da estrutura interna já forneçam o que você precisa.However, avoid creating and using filters purely for logging purposes, since the built-in framework logging features may already provide what you need. Se você for adicionar o registro em log a seus filtros, ele deve se concentrar em questões referentes ao domínio de negócios ou ao comportamento específico de seu filtro, em vez de ações do MVC ou outros eventos da estrutura.If you're going to add logging to your filters, it should focus on business domain concerns or behavior specific to your filter, rather than MVC actions or other framework events.

ServiceFilterAttributeServiceFilterAttribute

Tipos de implementação do filtro de serviço são registrados em DI.Service filter implementation types are registered in DI. Um ServiceFilterAttribute recupera uma instância do filtro da DI.A ServiceFilterAttribute retrieves an instance of the filter from DI. Adicione o ServiceFilterAttribute ao contêiner em Startup.ConfigureServices e faça uma referência a ele em um atributo [ServiceFilter]:Add the ServiceFilterAttribute to the container in Startup.ConfigureServices, and reference it in a [ServiceFilter] attribute:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", 
            "Result filter added to MvcOptions.Filters")); // an instance
        options.Filters.Add(typeof(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}
[ServiceFilter(typeof(AddHeaderFilterWithDi))]
public IActionResult Index()
{
    return View();
}

Ao usar ServiceFilterAttribute, configurar IsReusable é uma dica de que a instância de filtro pode ser reutilizada fora do escopo de solicitação em que ele foi criada.When using ServiceFilterAttribute, setting IsReusable is a hint that the filter instance may be reused outside of the request scope it was created within. A estrutura não fornece garantias de que uma única instância do filtro vá ser criada ou que o filtro não será solicitado novamente do contêiner de DI em algum momento posterior.The framework provides no guarantees that a single instance of the filter will be created or the filter will not be re-requested from the DI container at some later point. Evite usar IsReusable ao usar um filtro que dependa dos serviços com um tempo de vida diferente de singleton.Avoid using IsReusable when using a filter that depends on services with a lifetime other than singleton.

Usar ServiceFilterAttribute sem registrar o tipo de filtro gera uma exceção:Using ServiceFilterAttribute without registering the filter type results in an exception:

System.InvalidOperationException: No service for type
'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.

ServiceFilterAttribute implementa IFilterFactory.ServiceFilterAttribute implements IFilterFactory. IFilterFactory expõe o método CreateInstance para criar uma instância de IFilterMetadata.IFilterFactory exposes the CreateInstance method for creating an IFilterMetadata instance. O método CreateInstance carrega o tipo especificado do contêiner de serviços (DI).The CreateInstance method loads the specified type from the services container (DI).

TypeFilterAttributeTypeFilterAttribute

O TypeFilterAttribute é semelhante ao ServiceFilterAttribute, mas seu tipo não é resolvido diretamente por meio do contêiner de DI.TypeFilterAttribute is similar to ServiceFilterAttribute, but its type isn't resolved directly from the DI container. Ele cria uma instância do tipo usando Microsoft.Extensions.DependencyInjection.ObjectFactory.It instantiates the type by using Microsoft.Extensions.DependencyInjection.ObjectFactory.

Por causa dessa diferença:Because of this difference:

  • Os tipos que são referenciados usando o TypeFilterAttribute não precisam ser registrados no contêiner primeiro.Types that are referenced using the TypeFilterAttribute don't need to be registered with the container first. As dependências deles são atendidas pelo contêiner.They do have their dependencies fulfilled by the container.
  • Opcionalmente, o TypeFilterAttribute pode aceitar argumentos de construtor para o tipo.TypeFilterAttribute can optionally accept constructor arguments for the type.

Ao usar TypeFilterAttribute, configurar IsReusable é uma dica de que a instância de filtro pode ser reutilizada fora do escopo de solicitação em que ele foi criada.When using TypeFilterAttribute, setting IsReusable is a hint that the filter instance may be reused outside of the request scope it was created within. A estrutura não fornece nenhuma garantia de que uma única instância do filtro será criada.The framework provides no guarantees that a single instance of the filter will be created. Evite usar IsReusable ao usar um filtro que dependa dos serviços com um tempo de vida diferente de singleton.Avoid using IsReusable when using a filter that depends on services with a lifetime other than singleton.

O exemplo a seguir demonstra como passar argumentos para um tipo usando TypeFilterAttribute:The following example demonstrates how to pass arguments to a type using TypeFilterAttribute:

[TypeFilter(typeof(AddHeaderAttribute),
    Arguments = new object[] { "Author", "Steve Smith (@ardalis)" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}

IFilterFactory implementado em seu atributoIFilterFactory implemented on your attribute

Se você tiver um filtro que:If you have a filter that:

  • Não exija nenhum argumento.Doesn't require any arguments.
  • Tenha dependências de construtor que precisem ser atendidas pela DI.Has constructor dependencies that need to be filled by DI.

Você pode usar seu próprio atributo nomeado em classes e métodos em vez de [TypeFilter(typeof(FilterType))]).You can use your own named attribute on classes and methods instead of [TypeFilter(typeof(FilterType))]). O filtro a seguir mostra como isso pode ser implementado:The following filter shows how this can be implemented:

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl))
    {
    }

    private class SampleActionFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;
        public SampleActionFilterImpl(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _logger.LogInformation("Business action starting...");
            // perform some business logic work

        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // perform some business logic work
            _logger.LogInformation("Business action completed.");
        }
    }
}

Esse filtro pode ser aplicado a classes ou métodos usando a sintaxe [SampleActionFilter], em vez de precisar usar [TypeFilter] ou [ServiceFilter].This filter can be applied to classes or methods using the [SampleActionFilter] syntax, instead of having to use [TypeFilter] or [ServiceFilter].

Filtros de autorizaçãoAuthorization filters

Filtros de autorização:Authorization filters:

  • Controlam o acesso aos métodos de ação.Control access to action methods.
  • São os primeiros filtros a serem executados no pipeline de filtro.Are the first filters to be executed within the filter pipeline.
  • Têm um método anterior, mas não têm um método posterior.Have a before method, but no after method.

Você deve escrever somente um filtro de autorização personalizado se estiver escrevendo sua própria estrutura de autorização.You should only write a custom authorization filter if you are writing your own authorization framework. Prefira configurar suas políticas de autorização ou escrever uma política de autorização personalizada em vez de escrever um filtro personalizado.Prefer configuring your authorization policies or writing a custom authorization policy over writing a custom filter. A implementação do filtro interno é responsável somente por chamar o sistema de autorização.The built-in filter implementation is just responsible for calling the authorization system.

Você não deve gerar exceções dentro de filtros de autorização, pois nada tratará a exceção (os filtros de exceção não as tratarão).You shouldn't throw exceptions within authorization filters, since nothing will handle the exception (exception filters won't handle them). Considere a possibilidade de emitir um desafio quando ocorrer uma exceção.Consider issuing a challenge when an exception occurs.

Saiba mais sobre Autorização.Learn more about Authorization.

Filtros de recursoResource filters

  • Implementam a interface IResourceFilter ou IAsyncResourceFilter.Implement either the IResourceFilter or IAsyncResourceFilter interface,
  • Suas execuções encapsulam a maior parte do pipeline de filtro.Their execution wraps most of the filter pipeline.
  • Somente os Filtros de autorização são executados antes dos Filtros de recurso.Only Authorization filters run before Resource filters.

Os filtros de recursos são úteis para causar um curto-circuito na maior parte do trabalho que uma solicitação faz.Resource filters are useful to short-circuit most of the work a request is doing. Por exemplo, um filtro de cache poderá evitar o restante do pipeline se a resposta estiver no cache.For example, a caching filter can avoid the rest of the pipeline if the response is in the cache.

O filtro de recurso com curto-circuito mostrado anteriormente é um exemplo de filtro de recurso.The short circuiting resource filter shown earlier is one example of a resource filter. Outro exemplo é DisableFormValueModelBindingAttribute:Another example is DisableFormValueModelBindingAttribute:

  • Essa opção impedirá o model binding de acessar os dados do formulário.It prevents model binding from accessing the form data.
  • Ela é útil para uploads de arquivos grandes e para impedir que o formulário seja lido na memória.It's useful for large file uploads and want to prevent the form from being read into memory.

Filtros de açãoAction filters

Filtros de ação:Action filters:

  • Implementam a interface IActionFilter ou IAsyncActionFilter.Implement either the IActionFilter or IAsyncActionFilter interface.
  • A execução deles envolve a execução de métodos de ação.Their execution surrounds the execution of action methods.

Veja um exemplo de filtro de ação:Here's a sample action filter:

public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // do something before the action executes
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // do something after the action executes
    }
}

ActionExecutingContext fornece as seguintes propriedades:The ActionExecutingContext provides the following properties:

  • ActionArguments – permite manipular as entradas para a ação.ActionArguments - lets you manipulate the inputs to the action.
  • Controller – permite manipular a instância do controlador.Controller - lets you manipulate the controller instance.
  • Result – defini-lo faz um curto-circuito da execução do método de ação e dos filtros de ação posteriores.Result - setting this short-circuits execution of the action method and subsequent action filters. Apresentar uma exceção também impete a execução do método de ação e dos filtros posteriores, mas isso é tratado como uma falha, e não como um resultado bem-sucedido.Throwing an exception also prevents execution of the action method and subsequent filters, but is treated as a failure instead of a successful result.

ActionExecutedContext fornece Controller e Result, bem como as seguintes propriedades:The ActionExecutedContext provides Controller and Result plus the following properties:

  • Canceled – será verdadeiro se a execução da ação tiver sofrido curto-circuito por outro filtro.Canceled - will be true if the action execution was short-circuited by another filter.
  • Exception – não será nulo se a ação ou um filtro de ação posterior tiver apresentado uma exceção.Exception - will be non-null if the action or a subsequent action filter threw an exception. Definir essa propriedade como nula “manipula” uma exceção efetivamente e Result será executado como se tivesse sido retornado do método de ação normalmente.Setting this property to null effectively 'handles' an exception, and Result will be executed as if it were returned from the action method normally.

Para um IAsyncActionFilter, uma chamada para o ActionExecutionDelegate:For an IAsyncActionFilter, a call to the ActionExecutionDelegate:

  • Executa todos os próximos filtros de ação e o método de ação.Executes any subsequent action filters and the action method.
  • Retorna ActionExecutedContext.returns ActionExecutedContext.

Para fazer um curto-circuito, atribua ActionExecutingContext.Result a uma instância de resultado e não chame o ActionExecutionDelegate.To short-circuit, assign ActionExecutingContext.Result to some result instance and don't call the ActionExecutionDelegate.

A estrutura fornece um ActionFilterAttribute abstrato que você pode colocar em uma subclasse.The framework provides an abstract ActionFilterAttribute that you can subclass.

Você poderá usar um filtro de ação para validar o estado do modelo e retornar erros se o estado for inválido:You can use an action filter to validate model state and return any errors if the state is invalid:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }
}

O método OnActionExecuted é executado depois do método de ação e pode ver e manipular os resultados da ação por meio da propriedade ActionExecutedContext.Result.The OnActionExecuted method runs after the action method and can see and manipulate the results of the action through the ActionExecutedContext.Result property. ActionExecutedContext.Canceled será definido como verdadeiro se a execução da ação tiver sofrido curto-circuito por outro filtro.ActionExecutedContext.Canceled will be set to true if the action execution was short-circuited by another filter. ActionExecutedContext.Exception será definido como um valor não nulo se a ação ou um filtro de ação posterior tiver apresentado uma exceção.ActionExecutedContext.Exception will be set to a non-null value if the action or a subsequent action filter threw an exception. Definindo ActionExecutedContext.Exception como nulo:Setting ActionExecutedContext.Exception to null:

  • 'Trata' efetivamente uma exceção.Effectively 'handles' an exception.
  • ActionExectedContext.Result é executado como se fosse retornado normalmente do método de ação.ActionExectedContext.Result is executed as if it were returned normally from the action method.

Filtros de exceçãoException filters

Filtros de exceção implementam a interface IExceptionFilter ou IAsyncExceptionFilter.Exception filters implement either the IExceptionFilter or IAsyncExceptionFilter interface. Eles podem ser usados para implementar políticas de tratamento de erro comuns para um aplicativo.They can be used to implement common error handling policies for an app.

O exemplo de filtro de exceção a seguir usa uma exibição de erro do desenvolvedor personalizada para exibir detalhes sobre exceções que ocorrem quando o aplicativo está em desenvolvimento:The following sample exception filter uses a custom developer error view to display details about exceptions that occur when the app is in development:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly IHostingEnvironment _hostingEnvironment;
    private readonly IModelMetadataProvider _modelMetadataProvider;

    public CustomExceptionFilterAttribute(
        IHostingEnvironment hostingEnvironment,
        IModelMetadataProvider modelMetadataProvider)
    {
        _hostingEnvironment = hostingEnvironment;
        _modelMetadataProvider = modelMetadataProvider;
    }

    public override void OnException(ExceptionContext context)
    {
        if (!_hostingEnvironment.IsDevelopment())
        {
            // do nothing
            return;
        }
        var result = new ViewResult {ViewName = "CustomError"};
        result.ViewData = new ViewDataDictionary(_modelMetadataProvider,context.ModelState);
        result.ViewData.Add("Exception", context.Exception);
        // TODO: Pass additional detailed data via ViewData
        context.Result = result;
    }
}

Filtros de exceção:Exception filters:

  • Não têm eventos anteriores nem posteriores.Don't have before and after events.
  • Implementam OnException ou OnExceptionAsync.Implement OnException or OnExceptionAsync.
  • Tratam as exceções sem tratamento que ocorrem na criação do controlador, no model binding, nos filtros de ação ou nos métodos de ação.Handle unhandled exceptions that occur in controller creation, model binding, action filters, or action methods.
  • Não capturam as exceções que ocorrem em Filtros de recurso, em Filtros de resultado ou na execução do Resultado de MVC.Do not catch exceptions that occur in Resource filters, Result filters, or MVC Result execution.

Para tratar uma exceção, defina a propriedade ExceptionContext.ExceptionHandled como verdadeiro ou grave uma resposta.To handle an exception, set the ExceptionContext.ExceptionHandled property to true or write a response. Isso interrompe a propagação da exceção.This stops propagation of the exception. Um Filtro de exceção não pode transformar uma exceção em "êxito".An Exception filter can't turn an exception into a "success". Somente um filtro de ação pode fazer isso.Only an Action filter can do that.

Observação

No ASP.NET Core 1.1, a resposta não será enviada se você definir ExceptionHandled como true e gravar uma resposta.In ASP.NET Core 1.1, the response isn't sent if you set ExceptionHandled to true and write a response. Nesse cenário, o ASP.NET Core 1.0 envia a resposta e o ASP.NET Core 1.1.2 retorna ao comportamento do 1.0.In that scenario, ASP.NET Core 1.0 does send the response, and ASP.NET Core 1.1.2 will return to the 1.0 behavior. Para obter mais informações, consulte problema #5594 no repositório do GitHub.For more information, see issue #5594 in the GitHub repository.

Filtros de exceção:Exception filters:

  • São bons para interceptar as exceções que ocorrem nas ações de MVC.Are good for trapping exceptions that occur within MVC actions.
  • Não são tão flexíveis quanto o middleware de tratamento de erro.Are not as flexible as error handling middleware.

Prefira o middleware para tratamento de exceção.Prefer middleware for exception handling. Use filtros de exceção somente quando você precisar fazer o tratamento de erro de forma diferente com base na ação de MVC escolhida.Use exception filters only where you need to do error handling differently based on which MVC action was chosen. Por exemplo, seu aplicativo pode ter métodos de ação para os pontos de extremidade da API e para modos de exibição/HTML.For example, your app might have action methods for both API endpoints and for views/HTML. Os pontos de extremidade da API podem retornar informações de erro como JSON, enquanto as ações baseadas em modo de exibição podem retornar uma página de erro como HTML.The API endpoints could return error information as JSON, while the view-based actions could return an error page as HTML.

O ExceptionFilterAttribute pode tornar-se uma subclasse.The ExceptionFilterAttribute can be subclassed.

Filtros de resultadoResult filters

  • Implementam a interface IResultFilter ou IAsyncResultFilter.Implement either the IResultFilter or IAsyncResultFilter interface.
  • A execução deles envolve a execução de resultados de ação.Their execution surrounds the execution of action results.

Veja um exemplo de um filtro de resultado que adiciona um cabeçalho HTTP.Here's an example of a Result filter that adds an HTTP header.

public class AddHeaderFilterWithDi : IResultFilter
{
    private ILogger _logger;
    public AddHeaderFilterWithDi(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<AddHeaderFilterWithDi>();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var headerName = "OnResultExecuting";
        context.HttpContext.Response.Headers.Add(
            headerName, new string[] { "ResultExecutingSuccessfully" });
        _logger.LogInformation($"Header added: {headerName}");
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // Can't add to headers here because response has already begun.
    }
}

O tipo de resultado que está sendo executado depende da ação em questão.The kind of result being executed depends on the action in question. Uma ação de MVC que retorna um modo de exibição incluiria todo o processamento de Razor como parte do ViewResult em execução.An MVC action returning a view would include all razor processing as part of the ViewResult being executed. Um método de API pode executar alguma serialização como parte da execução do resultado.An API method might perform some serialization as part of the execution of the result. Saiba mais sobre resultados de açãoLearn more about action results

Filtros de resultado são executados somente para resultados bem-sucedidos – quando a ação ou filtros da ação produzem um resultado de ação.Result filters are only executed for successful results - when the action or action filters produce an action result. Filtros de resultado não são executados quando filtros de exceção tratam uma exceção.Result filters are not executed when exception filters handle an exception.

O método OnResultExecuting pode fazer o curto-circuito da execução do resultado da ação e dos filtros de resultados posteriores definindo ResultExecutingContext.Cancel como verdadeiro.The OnResultExecuting method can short-circuit execution of the action result and subsequent result filters by setting ResultExecutingContext.Cancel to true. De modo geral, você deve gravar no objeto de resposta ao fazer um curto-circuito para evitar gerar uma resposta vazia.You should generally write to the response object when short-circuiting to avoid generating an empty response. A geração de uma exceção vai:Throwing an exception will:

  • Impedir a execução do resultado da ação e dos próximos filtros.Prevent execution of the action result and subsequent filters.
  • Ser tratada como uma falha e não como um resultado com êxito.Be treated as a failure instead of a successful result.

Quando o método OnResultExecuted é executado, a resposta provavelmente foi enviada ao cliente e não pode mais ser alterada (a menos que uma exceção tenha sido apresentada).When the OnResultExecuted method runs, the response has likely been sent to the client and cannot be changed further (unless an exception was thrown). ResultExecutedContext.Canceled será definido como verdadeiro se a execução do resultado da ação tiver sofrido curto-circuito por outro filtro.ResultExecutedContext.Canceled will be set to true if the action result execution was short-circuited by another filter.

ResultExecutedContext.Exception será definido como um valor não nulo se o resultado da ação ou um filtro de resultado posterior tiver apresentado uma exceção.ResultExecutedContext.Exception will be set to a non-null value if the action result or a subsequent result filter threw an exception. Definir Exception para como nulo “trata” uma exceção com eficiência e impede que a exceção seja apresentada novamente pelo MVC posteriormente no pipeline.Setting Exception to null effectively 'handles' an exception and prevents the exception from being rethrown by MVC later in the pipeline. Quando está tratando uma exceção em um filtro de resultado, talvez você não possa gravar dados na resposta.When you're handling an exception in a result filter, you might not be able to write any data to the response. Se o resultado da ação for apresentado durante sua execução e os cabeçalhos já tiverem sido liberados para o cliente, não haverá nenhum mecanismo confiável para enviar um código de falha.If the action result throws partway through its execution, and the headers have already been flushed to the client, there's no reliable mechanism to send a failure code.

Para um IAsyncResultFilter, uma chamada para await next no ResultExecutionDelegate executa qualquer filtro de resultado posterior e o resultado da ação.For an IAsyncResultFilter a call to await next on the ResultExecutionDelegate executes any subsequent result filters and the action result. Para fazer um curto-circuito, defina ResultExecutingContext.Cancel para verdadeiro e não chame ResultExectionDelegate.To short-circuit, set ResultExecutingContext.Cancel to true and don't call the ResultExectionDelegate.

A estrutura fornece um ResultFilterAttribute abstrato que você pode colocar em uma subclasse.The framework provides an abstract ResultFilterAttribute that you can subclass. A classe AddHeaderAttribute mostrada anteriormente é um exemplo de atributo de filtro de resultado.The AddHeaderAttribute class shown earlier is an example of a result filter attribute.

Usando middleware no pipeline de filtrosUsing middleware in the filter pipeline

Filtros de recursos funcionam como middleware, no sentido em que envolvem a execução de tudo o que vem depois no pipeline.Resource filters work like middleware in that they surround the execution of everything that comes later in the pipeline. Mas os filtros diferem do middleware porque fazem parte do MVC, o que significa que eles têm acesso ao contexto e a constructos do MVC.But filters differ from middleware in that they're part of MVC, which means that they have access to MVC context and constructs.

No ASP.NET Core 1.1, você pode usar o middleware no pipeline de filtros.In ASP.NET Core 1.1, you can use middleware in the filter pipeline. Talvez você queira fazer isso se tiver um componente de middleware que precisa acessar dados de rota do MVC ou que precisa ser executado somente para determinados controladores ou ações.You might want to do that if you have a middleware component that needs access to MVC route data, or one that should run only for certain controllers or actions.

Para usar o middleware como um filtro, crie um tipo com um método Configure que especifica o middleware que você deseja injetar no pipeline de filtros.To use middleware as a filter, create a type with a Configure method that specifies the middleware that you want to inject into the filter pipeline. Veja um exemplo que usa o middleware de localização para estabelecer a cultura atual para uma solicitação:Here's an example that uses the localization middleware to establish the current culture for a request:

public class LocalizationPipeline
{
    public void Configure(IApplicationBuilder applicationBuilder)
    {
        var supportedCultures = new[]
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr")
        };

        var options = new RequestLocalizationOptions
        {

            DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        };
        options.RequestCultureProviders = new[] 
            { new RouteDataRequestCultureProvider() { Options = options } };

        applicationBuilder.UseRequestLocalization(options);
    }
}

Depois, você pode usar o MiddlewareFilterAttribute para executar o middleware para um controlador ou ação selecionada ou para executá-lo globalmente:You can then use the MiddlewareFilterAttribute to run the middleware for a selected controller or action or globally:

[Route("{culture}/[controller]/[action]")]
[MiddlewareFilter(typeof(LocalizationPipeline))]
public IActionResult CultureFromRouteData()
{
    return Content($"CurrentCulture:{CultureInfo.CurrentCulture.Name},"
        + $"CurrentUICulture:{CultureInfo.CurrentUICulture.Name}");
}

Filtros de middleware são executados no mesmo estágio do pipeline de filtros que filtros de recurso, antes do model binding e depois do restante do pipeline.Middleware filters run at the same stage of the filter pipeline as Resource filters, before model binding and after the rest of the pipeline.

Próximas açõesNext actions

Para fazer experiências com filtros, baixe, teste e modifique o exemplo.To experiment with filters, download, test and modify the sample.