Filtres dans ASP.NET CoreFilters in ASP.NET Core

Par Rick Anderson, Tom Dykstra et Steve SmithBy Rick Anderson, Tom Dykstra, and Steve Smith

Les filtres dans ASP.NET Core MVC vous permettent d’exécuter du code avant ou après des étapes spécifiques du pipeline de traitement des requêtes.Filters in ASP.NET Core MVC allow you to run code before or after specific stages in the request processing pipeline.

Important

Cette rubrique ne s’applique pas aux pages Razor.This topic does not apply to Razor Pages. ASP.NET Core 2.1 et ultérieur prend en charge IPageFilter et IAsyncPageFilter pour les pages Razor.ASP.NET Core 2.1 and later supports IPageFilter and IAsyncPageFilter for Razor Pages. Pour plus d’informations, consultez Méthodes de filtre pour les pages Razor.For more information, see Filter methods for Razor Pages.

Les filtres intégrés gèrent notamment les tâches suivantes :Built-in filters handle tasks such as:

  • Autorisation (empêcher un utilisateur non autorisé d’accéder à des ressources).Authorization (preventing access to resources a user isn't authorized for).
  • Vérification de l’utilisation du protocole HTTPS par toutes les requêtes.Ensuring that all requests use HTTPS.
  • Mise en cache des réponses (court-circuitage du pipeline de requêtes pour retourner une réponse mise en cache).Response caching (short-circuiting the request pipeline to return a cached response).

Il est possible de créer des filtres personnalisés pour gérer les problèmes transversaux.Custom filters can be created to handle cross-cutting concerns. Les filtres peuvent éviter la duplication de code entre les actions.Filters can avoid duplicating code across actions. Par exemple, un filtre d’exceptions de gestion des erreurs peut servir à consolider la gestion des erreurs.For example, an error handling exception filter could consolidate error handling.

Affichez ou téléchargez un exemple depuis GitHub.View or download sample from GitHub.

Fonctionnement des filtresHow do filters work?

Les filtres s’exécutent dans le pipeline des appels d’actions MVC, parfois appelé pipeline de filtres.Filters run within the MVC action invocation pipeline, sometimes referred to as the filter pipeline. Le pipeline de filtres s’exécute après la sélection par MVC de l’action à exécuter.The filter pipeline runs after MVC selects the action to execute.

La requête est traitée via un autre intergiciel, un intergiciel de routage, une sélection d’action et le pipeline d’appels d’actions MVC.

Types de filtresFilter types

Chaque type de filtre est exécuté dans une étape différente du pipeline de filtres.Each filter type is executed at a different stage in the filter pipeline.

  • Les filtres d’autorisations s’exécutent en premier et sont utilisés pour déterminer si l’utilisateur actif est autorisé pour la requête active.Authorization filters run first and are used to determine whether the current user is authorized for the current request. Ils peuvent court-circuiter le pipeline si une requête n’est pas autorisée.They can short-circuit the pipeline if a request is unauthorized.

  • Les filtres de ressources sont les premiers à traiter une requête après autorisation.Resource filters are the first to handle a request after authorization. Ils peuvent exécuter du code avant le reste du pipeline de filtres, et après que le reste du pipeline est terminé.They can run code before the rest of the filter pipeline, and after the rest of the pipeline has completed. Ils sont pratiques pour implémenter la mise en cache ou pour court-circuiter le pipeline de filtres pour des raisons de performances.They're useful to implement caching or otherwise short-circuit the filter pipeline for performance reasons. Comme ils s’exécutent avant la liaison de données, ils peuvent l’influencer.They run before model binding, so they can influence model binding.

  • Les filtres d’actions peuvent exécuter du code juste avant et juste après l’appel d’une méthode d’action individuelle.Action filters can run code immediately before and after an individual action method is called. Ils peuvent être utilisés pour manipuler les arguments passés à une action et le résultat retourné depuis l’action.They can be used to manipulate the arguments passed into an action and the result returned from the action.

  • Les filtres d’exceptions sont utilisés pour appliquer des stratégies globales à des exceptions non gérées qui se produisent avant que des éléments aient été écrits dans le corps de la réponse.Exception filters are used to apply global policies to unhandled exceptions that occur before anything has been written to the response body.

  • Les filtres de résultats peuvent exécuter du code juste avant et juste après l’exécution des résultats d’une action individuelle.Result filters can run code immediately before and after the execution of individual action results. Ils s’exécutent uniquement au terme de l’exécution de la méthode d’action.They run only when the action method has executed successfully. Ils sont utiles pour la logique qui doit entourer l’exécution de la vue ou du formateur.They are useful for logic that must surround view or formatter execution.

Le diagramme suivant montre comment ces types de filtres interagissent dans le pipeline de filtres.The following diagram shows how these filter types interact in the filter pipeline.

La requête est traitée à travers les filtres d’autorisations, les filtres de ressources, la liaison de modèle, les filtres d’actions, l’exécution d’actions et la conversion des résultats d’actions, les filtres d’exceptions, les filtres de résultats et l’exécution de résultats.

ImplémentationImplementation

Les filtres prennent en charge les implémentations synchrones et asynchrones via différentes définitions d’interface.Filters support both synchronous and asynchronous implementations through different interface definitions.

Les filtres synchrones qui peuvent exécuter du code avant et après leur étape de pipeline définissent les méthodes OnStageExecuting et OnStageExecuted.Synchronous filters that can run code both before and after their pipeline stage define OnStageExecuting and OnStageExecuted methods. Par exemple, OnActionExecuting est appelée avant l’appel de la méthode d’action, et OnActionExecuted est appelée après que la méthode d’action retourne.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
        }
    }
}

Les filtres asynchrones définissent une méthode OnStageExecutionAsync.Asynchronous filters define a single OnStageExecutionAsync method. Cette méthode prend un déléguéFilterTypeExecutionDelegate qui exécute l’étape du pipeline du filtre.This method takes a FilterTypeExecutionDelegate delegate which executes the filter's pipeline stage. Par exemple, ActionExecutionDelegate appelle la méthode d’action ou le filtre d’action suivant, et vous pouvez exécuter du code avant et après l’appel de cette méthode.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
        }
    }
}

Vous pouvez implémenter des interfaces pour plusieurs étapes de filtres dans une même classe.You can implement interfaces for multiple filter stages in a single class. Par exemple, la classe ActionFilterAttribute implémente IActionFilter, IResultFilter et leurs équivalents asynchrones.For example, the ActionFilterAttribute class implements IActionFilter, IResultFilter, and their async equivalents.

Note

Implémentez la version synchrone ou bien la version asynchrone d’une interface de filtre, mais pas les deux.Implement either the synchronous or the async version of a filter interface, not both. Le framework vérifie d’abord si le filtre implémente l’interface asynchrone et, le cas échéant, il appelle cette interface.The framework checks first to see if the filter implements the async interface, and if so, it calls that. Dans le cas contraire, il appelle la ou les méthodes de l’interface synchrone.If not, it calls the synchronous interface's method(s). Si vous implémentez les deux interfaces sur une même classe, seule la méthode asynchrone est appelée.If you were to implement both interfaces on one class, only the async method would be called. Quand vous utilisez des classes abstraites comme ActionFilterAttribute, vous devez remplacer seulement les méthodes synchrones ou bien la méthode asynchrone pour chaque type de filtre.When using abstract classes like ActionFilterAttribute you would override only the synchronous methods or the async method for each filter type.

IFilterFactoryIFilterFactory

IFilterFactory implémente IFilterMetadata.IFilterFactory implements IFilterMetadata. Par conséquent, une instance de IFilterFactory peut être utilisée comme instance de IFilterMetadata n’importe où dans le pipeline de filtres.Therefore, an IFilterFactory instance can be used as an IFilterMetadata instance anywhere in the filter pipeline. Quand le framework se prépare à appeler le filtre, il tente d’effectuer un cast en IFilterFactory.When the framework prepares to invoke the filter, it attempts to cast it to an IFilterFactory. Si ce cast réussit, la méthode CreateInstance est appelée pour créer l’instance de IFilterMetadata qui sera appelée.If that cast succeeds, the CreateInstance method is called to create the IFilterMetadata instance that will be invoked. La conception est flexible, car il n’est pas nécessaire de définir explicitement le pipeline de filtres exact quand l’application démarre.This provides a flexible design, since the precise filter pipeline doesn't need to be set explicitly when the app starts.

Une autre approche pour la création de filtres est d’implémenter IFilterFactory sur vos propres implémentations d’attributs :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;
        }
    }
}

Attributs de filtre intégrésBuilt-in filter attributes

Le framework inclut les filtres intégrés basés sur des attributs que vous pouvez définir dans une sous-classe et personnaliser.The framework includes built-in attribute-based filters that you can subclass and customize. Par exemple, le filtre de résultats suivant ajoute un en-tête à la réponse.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);
        }
    }
}

Les attributs autorisent les filtres à accepter des arguments, comme montré dans l’exemple ci-dessus.Attributes allow filters to accept arguments, as shown in the example above. Vous pouvez ajouter cet attribut à une méthode de contrôleur ou d’action, et spécifier le nom et la valeur de l’en-tête 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.");
    }

Le résultat de l’action Index est montré ci-dessous : les en-têtes de réponse apparaissent dans la partie inférieure droite.The result of the Index action is shown below - the response headers are displayed on the bottom right.

Les outils de développement de Microsoft Edge affichant des en-têtes de réponse, notamment l’auteur Steve Smith

Plusieurs des interfaces de filtre ont des attributs correspondants qui peuvent être utilisés comme classes de base pour des implémentations personnalisées.Several of the filter interfaces have corresponding attributes that can be used as base classes for custom implementations.

Les attributs de filtre :Filter attributes:

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

TypeFilterAttribute et ServiceFilterAttribute sont expliqués plus loin dans cet article.TypeFilterAttribute and ServiceFilterAttribute are explained later in this article.

Étendues de filtre et ordre d’exécutionFilter scopes and order of execution

Un filtre peut être ajouté au pipeline à une parmi trois étendues.A filter can be added to the pipeline at one of three scopes. Vous pouvez ajouter un filtre à une méthode d’action particulière ou à une classe de contrôleur en utilisant un attribut.You can add a filter to a particular action method or to a controller class by using an attribute. Vous pouvez également enregistrer un filtre globalement pour l’ensemble des contrôleurs et des actions.Or you can register a filter globally for all controllers and actions. Pour ajouter des filtres globalement, ajoutez-les à la collection MvcOptions.Filters dans 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>();
}

Ordre d’exécution par défautDefault order of execution

Quand il existe plusieurs filtres pour une étape particulière du pipeline, l’étendue détermine l’ordre par défaut de l’exécution du filtre.When there are multiple filters for a particular stage of the pipeline, scope determines the default order of filter execution. Les filtres globaux entourent les filtres de classe, qui à leur tour entourent les filtres de méthode.Global filters surround class filters, which in turn surround method filters. On parle parfois d’imbrication en « poupées russes », car chaque accroissement d’étendue englobe l’étendue précédente, comme une poupée gigogne.This is sometimes referred to as "Russian doll" nesting, as each increase in scope is wrapped around the previous scope, like a nesting doll. En règle générale, vous obtenez le comportement de remplacement souhaité sans avoir à déterminer l’ordre explicitement.You generally get the desired overriding behavior without having to explicitly determine ordering.

En raison de cette imbrication, le code après des filtres s’exécute dans l’ordre inverse du code avant.As a result of this nesting, the after code of filters runs in the reverse order of the before code. La séquence ressemble à ceci :The sequence looks like this:

  • Le code avant des filtres appliqués globalementThe before code of filters applied globally
    • Le code avant des filtres appliqués aux contrôleursThe before code of filters applied to controllers
      • Le code avant des filtres appliqués aux méthodes d’actionThe before code of filters applied to action methods
      • Le code après des filtres appliqués aux méthodes d’actionThe after code of filters applied to action methods
    • Le code après des filtres appliqués aux contrôleursThe after code of filters applied to controllers
  • Le code après des filtres appliqués globalementThe after code of filters applied globally

Voici un exemple qui illustre l’ordre dans lequel les méthodes de filtre sont appelées pour les filtres d’actions synchrones.Here's an example that illustrates the order in which filter methods are called for synchronous Action filters.

SéquenceSequence Étendue de filtreFilter scope Méthode de filtreFilter method
11 GlobalGlobal OnActionExecuting
22 ContrôleurController OnActionExecuting
33 MéthodeMethod OnActionExecuting
44 MéthodeMethod OnActionExecuted
55 ContrôleurController OnActionExecuted
66 GlobalGlobal OnActionExecuted

Cette séquence montre que :This sequence shows:

  • Le filtre de méthode est imbriqué dans le filtre de contrôleur.The method filter is nested within the controller filter.
  • Le filtre de contrôleur est imbriqué dans le filtre global.The controller filter is nested within the global filter.

En d’autres termes, si vous êtes à l’intérieur d’un méthode OnStageExecutionAsync d’un filtre asynchrone, tous les filtres avec une étendue plus étroite s’exécutent alors que votre code est sur la pile.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.

Note

Chaque contrôleur qui hérite de la classe de base Controller inclut des méthodes OnActionExecuting et OnActionExecuted.Every controller that inherits from the Controller base class includes OnActionExecuting and OnActionExecuted methods. Ces méthodes encapsulent les filtres qui s’exécutent pour une action donnée : OnActionExecuting est appelée avant tous les filtres, et OnActionExecuted est appelée après tous les filtres.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.

Remplacement de l’ordre par défautOverriding the default order

Vous pouvez remplacer la séquence d’exécution par défaut en implémentant IOrderedFilter.You can override the default sequence of execution by implementing IOrderedFilter. Cette interface expose une propriété Order qui est prioritaire sur l’étendue afin de déterminer l’ordre d’exécution.This interface exposes an Order property that takes precedence over scope to determine the order of execution. Un filtre avec une valeur Order inférieure verra son code avant exécuté avant celui d’un filtre avec une valeur plus élevée 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. Un filtre avec une valeur Order inférieure verra son code après exécuté après celui d’un filtre avec une valeur plus élevée 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. Vous pouvez définir la propriété Order en utilisant un paramètre de constructeur :You can set the Order property by using a constructor parameter:

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

Si vous avez les 3 mêmes filtres d’action de l’exemple précédent, mais que vous définissez la propriété Order du filtre de contrôleur et du filtre global respectivement sur 1 et sur 2, l’ordre d’exécution est inversé.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.

SéquenceSequence Étendue de filtreFilter scope Propriété OrderOrder property Méthode de filtreFilter method
11 MéthodeMethod 00 OnActionExecuting
22 ContrôleurController 11 OnActionExecuting
33 GlobalGlobal 22 OnActionExecuting
44 GlobalGlobal 22 OnActionExecuted
55 ContrôleurController 11 OnActionExecuted
66 MéthodeMethod 00 OnActionExecuted

La propriété Order prévaut sur l’étendue lors de la détermination de l’ordre dans lequel les filtres s’exécutent.The Order property trumps scope when determining the order in which filters will run. Les filtres sont d’abord classés par ordre, puis l’étendue est utilisée pour couper les liens.Filters are sorted first by order, then scope is used to break ties. Tous les filtres intégrés implémentent IOrderedFilter et affectent 0 à la valeur Order par défaut.All of the built-in filters implement IOrderedFilter and set the default Order value to 0. Pour les filtres intégrés, l’étendue détermine l’ordre, sauf si vous affectez à Order une valeur différente de zéro.For built-in filters, scope determines order unless you set Order to a non-zero value.

Annulation et court-circuitCancellation and short circuiting

Vous pouvez court-circuiter le pipeline de filtres à n’importe quel endroit en définissant la propriété Result sur le paramètre context fourni à la méthode de filtre.You can short-circuit the filter pipeline at any point by setting the Result property on the context parameter provided to the filter method. Par exemple, le filtre de ressources suivant empêche l’exécution du reste du pipeline.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)
        {
        }
    }
}

Dans le code suivant, les filtres ShortCircuitingResourceFilter et AddHeader ciblent tous deux la méthode d’action SomeResource.In the following code, both the ShortCircuitingResourceFilter and the AddHeader filter target the SomeResource action method. Voici le ShortCircuitingResourceFilter :The ShortCircuitingResourceFilter:

  • S’exécute en premier (puisqu’il s’agit d’un filtre de ressources et que AddHeader est un filtre d’action).Runs first, because it's a Resource Filter and AddHeader is an Action Filter.
  • Court-circuite le reste du pipeline.Short-circuits the rest of the pipeline.

Le filtre AddHeader ne s’exécute donc jamais pour l’action SomeResource.Therefore the AddHeader filter never runs for the SomeResource action. Ce comportement est le même si les deux filtres sont appliqués au niveau de la méthode d’action, à condition que ShortCircuitingResourceFilter soit exécuté en premier.This behavior would be the same if both filters were applied at the action method level, provided the ShortCircuitingResourceFilter ran first. ShortCircuitingResourceFilter s’exécute en premier en raison de son type de filtre ou de l’utilisation explicite de la propriété 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.");
    }

Injection de dépendancesDependency injection

Les filtres peuvent être ajoutés par type ou par instance.Filters can be added by type or by instance. Si vous ajoutez une instance, celle-ci sera utilisée pour chaque requête.If you add an instance, that instance will be used for every request. Si vous ajoutez un type, il sera activé par type, ce qui signifie qu’une instance sera créée pour chaque requête et toutes les dépendances du constructeur seront remplies par injection de dépendances.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). L’ajout d’un filtre par type équivaut à filters.Add(new TypeFilterAttribute(typeof(MyFilter))).Adding a filter by type is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).

Les filtres qui sont implémentés en tant qu’attributs et ajoutés directement à des classes de contrôleur ou à de méthodes d’action ne peut pas avoir de dépendances de constructeur fournies par injection de dépendances.Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by dependency injection (DI). La raison en est que les paramètres du constructeur des attributs doivent être fournis là où ils sont appliqués.This is because attributes must have their constructor parameters supplied where they're applied. Il s’agit d’une limitation de la façon dont les attributs fonctionnent.This is a limitation of how attributes work.

Si vos filtres ont des dépendances auxquelles vous devez accéder à partir de l’injection de dépendances, plusieurs approches sont prises en charge.If your filters have dependencies that you need to access from DI, there are several supported approaches. Vous pouvez appliquer votre filtre à une méthode de classe ou d’action de l’une des façons suivantes :You can apply your filter to a class or action method using one of the following:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • IFilterFactory implémenté sur votre attributIFilterFactory implemented on your attribute

Note

Un journaliseur est une dépendance que vous pouvez obtenir de l’injection de dépendances.One dependency you might want to get from DI is a logger. Évitez cependant de créer et d’utiliser des filtres uniquement à des fins de journalisation, car les fonctionnalités de journalisation intégrées du framework peuvent parfois fournir ce dont vous avez besoin.However, avoid creating and using filters purely for logging purposes, since the built-in framework logging features may already provide what you need. Si vous voulez ajouter une journalisation à vos filtres, elle doit être centrée sur les problèmes du domaine métier ou sur un comportement spécifique à votre filtre, au lieu de porter sur les actions de MVC ou sur d’autres événements du framework.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

Un ServiceFilter récupère une instance du filtre à partir de l’injection de dépendances.A ServiceFilter retrieves an instance of the filter from DI. Vous ajoutez le filtre au conteneur dans ConfigureServices, et vous le référencez dans un attribut ServiceFilter.You add the filter to the container in 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();
}

L’utilisation de ServiceFilter sans inscription du type de filtre provoque une exception :Using ServiceFilter without registering the filter type results in an exception:

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

L'objet ServiceFilterAttribute implémente l'objet IFilterFactory.ServiceFilterAttribute implements IFilterFactory. IFilterFactory expose la méthode CreateInstance pour la création d’une instance IFilterMetadata.IFilterFactory exposes the CreateInstance method for creating an IFilterMetadata instance. La méthode CreateInstance charge le type spécifié à partir du conteneur de services (injection de dépendances).The CreateInstance method loads the specified type from the services container (DI).

TypeFilterAttributeTypeFilterAttribute

TypeFilterAttribute est similaire à ServiceFilterAttribute, mais son type n’est pas résolu directement à partir du conteneur d’injection de dépendances.TypeFilterAttribute is similar to ServiceFilterAttribute, but its type isn't resolved directly from the DI container. Il instancie le type en utilisant Microsoft.Extensions.DependencyInjection.ObjectFactory.It instantiates the type by using Microsoft.Extensions.DependencyInjection.ObjectFactory.

En raison de cette différence :Because of this difference:

  • Les types qui sont référencés avec TypeFilterAttribute ne doivent pas d’abord être inscrits auprès du conteneur.Types that are referenced using the TypeFilterAttribute don't need to be registered with the container first. Leurs dépendances sont remplies par le conteneur.They do have their dependencies fulfilled by the container.
  • TypeFilterAttribute peut éventuellement accepter des arguments de constructeur pour le type.TypeFilterAttribute can optionally accept constructor arguments for the type.

L’exemple suivant montre comment passer des arguments à un type en utilisant 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}");
}

Si vous avez un filtre qui :If you have a filter that:

  • Ne nécessite pas d’arguments.Doesn't require any arguments.
  • A des dépendances de constructeur qui doivent être remplies par l’injection de dépendances.Has constructor dependencies that need to be filled by DI.

Vous pouvez utiliser votre propre attribut nommé sur les classes et méthodes à la place de [TypeFilter(typeof(FilterType))].You can use your own named attribute on classes and methods instead of [TypeFilter(typeof(FilterType))]). Le filtre suivant montre comment vous pouvez implémenter ceci :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.");
        }
    }
}

Ce filtre peut être appliqué à des classes ou des méthodes avec la syntaxe [SampleActionFilter], au lieu de devoir utiliser [TypeFilter] ou [ServiceFilter].This filter can be applied to classes or methods using the [SampleActionFilter] syntax, instead of having to use [TypeFilter] or [ServiceFilter].

Filtres d’autorisationsAuthorization filters

Les filtres d’autorisations :*Authorization filters:

  • Contrôlent l’accès aux méthodes d’action.Control access to action methods.
  • Sont les premiers filtres à être exécutée dans le pipeline de filtres.Are the first filters to be executed within the filter pipeline.
  • Ont une méthode avant, mais pas de méthode après.Have a before method, but no after method.

Vous devez écrire un filtre d’autorisation personnalisé seulement si vous écrivez votre propre framework d’autorisation.You should only write a custom authorization filter if you are writing your own authorization framework. Préférez la configuration de vos stratégies d’autorisation ou l’écriture d’une stratégie d’autorisation personnalisée à l’écriture d’un filtre personnalisé.Prefer configuring your authorization policies or writing a custom authorization policy over writing a custom filter. L’implémentation des filtres intégrés est responsable seulement de l’appel du système d’autorisation.The built-in filter implementation is just responsible for calling the authorization system.

Vous ne devez pas lever d’exceptions dans les filtres d’autorisations, car rien ne gère les exceptions (les filtres d’exceptions ne les gèrent pas).You shouldn't throw exceptions within authorization filters, since nothing will handle the exception (exception filters won't handle them). Songez à émettre un challenge quand une exception se produit.Consider issuing a challenge when an exception occurs.

Découvrez plus d’informations sur l’autorisation.Learn more about Authorization.

Filtres de ressourcesResource filters

  • Implémentez l’interface IResourceFilter ou IAsyncResourceFilter.Implement either the IResourceFilter or IAsyncResourceFilter interface,
  • Leur exécution inclut dans un wrapper la majeure partie du pipeline de filtres.Their execution wraps most of the filter pipeline.
  • Seuls les filtres d’autorisations s’exécutent avant les filtres de ressources.Only Authorization filters run before Resource filters.

Les filtres de ressources sont utiles pour court-circuiter la majeure partie du travail effectué par une requête.Resource filters are useful to short-circuit most of the work a request is doing. Par exemple, un filtre de mise en cache peut éviter le reste du pipeline si la réponse est dans le cache.For example, a caching filter can avoid the rest of the pipeline if the response is in the cache.

Le filtre de ressources de court-circuit montré plus haut est un exemple de filtre de ressources.The short circuiting resource filter shown earlier is one example of a resource filter. Un autre exemple est DisableFormValueModelBindingAttribute :Another example is DisableFormValueModelBindingAttribute:

  • Il empêche la liaison de données d’accéder aux données de formulaire.It prevents model binding from accessing the form data.
  • Il est utile pour les chargements de fichiers volumineux et pour empêcher que le formulaire ne soit lu en mémoire.It's useful for large file uploads and want to prevent the form from being read into memory.

Filtres d’actionsAction filters

Filtres d’actions :Action filters:

  • Implémentez l’interface IActionFilter ou IAsyncActionFilter.Implement either the IActionFilter or IAsyncActionFilter interface.
  • Leur exécution entoure l’exécution de méthodes d’action.Their execution surrounds the execution of action methods.

Voici un exemple de filtre d’actions :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 fournit les propriétés suivantes :The ActionExecutingContext provides the following properties:

  • ActionArguments : vous permet de manipuler les entrées de l’action.ActionArguments - lets you manipulate the inputs to the action.
  • Controller : vous permet de manipuler l’instance de contrôleur.Controller - lets you manipulate the controller instance.
  • Result : la définition de ce paramètre court-circuite l’exécution de la méthode d’action et les filtres d’actions suivants.Result - setting this short-circuits execution of the action method and subsequent action filters. Lever une exception empêche également l’exécution de la méthode d’action et des filtres suivants, mais elle est traitée comme une erreur au lieu d’un résultat correct.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 fournit Controller et Result, plus les propriétés suivantes :The ActionExecutedContext provides Controller and Result plus the following properties:

  • Canceled : sa valeur est true si l’exécution de l’action a été court-circuitée par un autre filtre.Canceled - will be true if the action execution was short-circuited by another filter.
  • Exception : sa valeur est non Null si l’action ou un filtre d’actions suivant a levé une exception.Exception - will be non-null if the action or a subsequent action filter threw an exception. La définition de cette propriété sur Null « gère » effectivement une exception, et Result est exécuté comme s’il avait été retourné normalement depuis la méthode d’action.Setting this property to null effectively 'handles' an exception, and Result will be executed as if it were returned from the action method normally.

Pour un IAsyncActionFilter, un appel à ActionExecutionDelegate :For an IAsyncActionFilter, a call to the ActionExecutionDelegate:

  • Exécute tous les filtres d’actions suivants et la méthode d’action.Executes any subsequent action filters and the action method.
  • Retourne ActionExecutedContext.returns ActionExecutedContext.

Pour court-circuiter, affectez ActionExecutingContext.Result à une instance de résultat et n’appelez pas le ActionExecutionDelegate.To short-circuit, assign ActionExecutingContext.Result to some result instance and don't call the ActionExecutionDelegate.

Le framework fournit un ActionFilterAttribute abstrait que vous pouvez placer dans une sous-classe.The framework provides an abstract ActionFilterAttribute that you can subclass.

Vous pouvez utiliser un filtre d’actions pour valider l’état du modèle et retourner des erreurs si l’état n’est pas valide :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);
            }
        }
    }
}

La méthode OnActionExecuted s’exécute après la méthode d’action, et peut voir et manipuler les résultats de l’action via la propriété 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 est défini sur true si l’exécution de l’action a été court-circuitée par un autre filtre.ActionExecutedContext.Canceled will be set to true if the action execution was short-circuited by another filter. ActionExecutedContext.Exception est défini sur une valeur non Null si l’action ou un filtre d’actions suivant a levé une exception.ActionExecutedContext.Exception will be set to a non-null value if the action or a subsequent action filter threw an exception. Le fait de définir ActionExecutedContext.Exception avec la valeur null :Setting ActionExecutedContext.Exception to null:

  • « Gère » effectivement une exception.Effectively 'handles' an exception.
  • ActionExectedContext.Result est exécuté comme s’il avait été retourné normalement à partir de la méthode d’action.ActionExectedContext.Result is executed as if it were returned normally from the action method.

Filtres d’exceptionsException filters

Les filtres d’exceptions implémentent l’interface IExceptionFilter ou IAsyncExceptionFilter.Exception filters implement either the IExceptionFilter or IAsyncExceptionFilter interface. Ils peuvent être utilisés pour implémenter des stratégies de gestion des erreurs courantes pour une application.They can be used to implement common error handling policies for an app.

L’exemple de filtre d’exceptions suivant utilise une vue personnalisée des erreurs pour le développeur, pour afficher des détails sur les exceptions qui se produisent pendant que l’application est en développement :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;
    }
}

Les filtres d’exceptions :Exception filters:

  • N’ont pas d’événements avant et après.Don't have before and after events.
  • Implémentent OnException ou OnExceptionAsync.Implement OnException or OnExceptionAsync.
  • Gèrent les exceptions non gérées qui se produisent dans la création des contrôleurs, la liaison de données, les filtres d’actions ou les méthodes d’action.Handle unhandled exceptions that occur in controller creation, model binding, action filters, or action methods.
  • N’interceptent pas les exceptions qui se produisent dans l’exécution des filtres de ressources, des filtres de résultats ou des résultats MVC.Do not catch exceptions that occur in Resource filters, Result filters, or MVC Result execution.

Pour gérer une exception, définissez la propriété ExceptionContext.ExceptionHandled ou écrivez une réponse.To handle an exception, set the ExceptionContext.ExceptionHandled property to true or write a response. Ceci arrête la propagation de l’exception.This stops propagation of the exception. Un filtre d’exceptions ne peut pas changer une exception en « réussite ».An Exception filter can't turn an exception into a "success". Seul un filtre d’actions peut le faire.Only an Action filter can do that.

Note

Dans ASP.NET Core 1.1, la réponse n’est pas envoyée si vous définissez ExceptionHandled avec la valeur true et que vous écrivez une réponse.In ASP.NET Core 1.1, the response isn't sent if you set ExceptionHandled to true and write a response. Dans ce scénario, ASP.NET Core 1.0 envoie la réponse, et ASP.NET Core 1.1.2 revient au comportement de la version 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. Pour plus d’informations, consultez le problème #5594 dans le dépôt GitHub.For more information, see issue #5594 in the GitHub repository.

Les filtres d’exceptions :Exception filters:

  • Conviennent pour intercepter des exceptions qui se produisent dans les actions MVC.Are good for trapping exceptions that occur within MVC actions.
  • N’offrent pas la même souplesse que le middleware (intergiciel) de gestion des erreurs.Are not as flexible as error handling middleware.

Privilégiez le middleware pour la gestion des exceptions.Prefer middleware for exception handling. Utilisez uniquement des filtres d’exceptions si vous devez gérer les erreurs différemment en fonction de l’action MVC choisie.Use exception filters only where you need to do error handling differently based on which MVC action was chosen. Par exemple, votre application peut avoir des méthodes d’action à la fois pour des points de terminaison d’API et pour des vues/HTML.For example, your app might have action methods for both API endpoints and for views/HTML. Les points de terminaison d’API peuvent retourner des informations d’erreur au format JSON, tandis que les actions basées sur une vue peuvent retourner une page d’erreur au format HTML.The API endpoints could return error information as JSON, while the view-based actions could return an error page as HTML.

ExceptionFilterAttribute peut être sous-classé.The ExceptionFilterAttribute can be subclassed.

Filtres de résultatsResult filters

  • Implémentez l’interface IResultFilter ou IAsyncResultFilter.Implement either the IResultFilter or IAsyncResultFilter interface.
  • Leur exécution entoure l’exécution de résultats d’action.Their execution surrounds the execution of action results.

Voici un exemple de filtre de résultats qui ajoute un en-tête 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.
    }
}

Le type de résultat à exécuter dépend de l’action en question.The kind of result being executed depends on the action in question. Une action MVC retournant une vue inclut tous les traitements Razor dans le cadre de la ViewResult à exécuter.An MVC action returning a view would include all razor processing as part of the ViewResult being executed. Une méthode d’API peut effectuer une sérialisation dans le cadre de l’exécution du résultat.An API method might perform some serialization as part of the execution of the result. Découvrez plus d’informations sur les résultats d’actions.Learn more about action results

Les filtres de résultats sont exécutés seulement pour les résultats qui sont des réussites, quand l’action ou les filtres d’actions produisent un résultat d’action.Result filters are only executed for successful results - when the action or action filters produce an action result. Les filtres de résultats ne sont pas exécutés quand les filtres d’exceptions gèrent une exception.Result filters are not executed when exception filters handle an exception.

La méthode OnResultExecuting peut court-circuiter l’exécution du résultat d’action et les filtres de résultats suivants en définissant ResultExecutingContext.Cancel sur true.The OnResultExecuting method can short-circuit execution of the action result and subsequent result filters by setting ResultExecutingContext.Cancel to true. D’une façon générale, vous devez écrire dans l’objet de réponse quand vous court-circuitez pour éviter de générer une réponse vide.You should generally write to the response object when short-circuiting to avoid generating an empty response. La levée d’une exception :Throwing an exception will:

  • Empêche l’exécution du résultat d’action et des filtres suivants.Prevent execution of the action result and subsequent filters.
  • Est traitée comme une erreur et non comme une réussite.Be treated as a failure instead of a successful result.

Quand la méthode OnResultExecuted s’exécute, la réponse a probablement déjà été envoyée au client et ne peut plus être changée (sauf si une exception a été levée).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 est défini sur true si l’exécution du résultat d’action a été court-circuitée par un autre filtre.ResultExecutedContext.Canceled will be set to true if the action result execution was short-circuited by another filter.

ResultExecutedContext.Exception est défini sur une valeur non Null si le résultat d’action ou un filtre de résultats suivant a levé une exception.ResultExecutedContext.Exception will be set to a non-null value if the action result or a subsequent result filter threw an exception. Le fait de définir Exception sur Null « gère » effectivement une exception et évite à l’exception d’être à nouveau levée par MVC plus loin dans le pipeline.Setting Exception to null effectively 'handles' an exception and prevents the exception from being rethrown by MVC later in the pipeline. Quand vous gérez une exception dans un filtre de résultats, il peut être impossible d’écrire des données dans la réponse.When you're handling an exception in a result filter, you might not be able to write any data to the response. Si le résultat d’une action lève une exception à mi-chemin de son exécution et que les en-têtes ont déjà été envoyés au client, il n’existe aucun mécanisme fiable pour envoyer un code d’échec.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.

Pour un IAsyncResultFilter, un appel à await next sur le ResultExecutionDelegate exécute tous les filtres de résultats suivants et le résultat de l’action.For an IAsyncResultFilter a call to await next on the ResultExecutionDelegate executes any subsequent result filters and the action result. Pour court-circuiter, définissez ResultExecutingContext.Cancel sur true et n’appelez pas le ResultExectionDelegate.To short-circuit, set ResultExecutingContext.Cancel to true and don't call the ResultExectionDelegate.

Le framework fournit un ResultFilterAttribute abstrait que vous pouvez placer dans une sous-classe.The framework provides an abstract ResultFilterAttribute that you can subclass. La classe AddHeaderAttribute ci-dessus est un exemple d’un attribut de filtre de résultats.The AddHeaderAttribute class shown earlier is an example of a result filter attribute.

Utilisation d’un intergiciel dans le pipeline de filtresUsing middleware in the filter pipeline

Les filtres de ressources fonctionnent comme un intergiciel dans la mesure où ils entourent l’exécution de tout ce qui vient plus tard dans le pipeline.Resource filters work like middleware in that they surround the execution of everything that comes later in the pipeline. Les filtres diffèrent cependant d’un intergiciel dans la mesure où ils font partie de MVC, ce qui signifie qu’ils ont accès au contexte et aux constructions MVC.But filters differ from middleware in that they're part of MVC, which means that they have access to MVC context and constructs.

Dans ASP.NET Core 1.1, vous pouvez utiliser un intergiciel dans le pipeline de filtres.In ASP.NET Core 1.1, you can use middleware in the filter pipeline. Vous pouvez faire cela si vous avez un composant d’intergiciel qui doit accéder aux données de route de MVC, ou qui doit s’exécuter seulement pour certains contrôleurs ou certaines actions.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.

Pour utiliser un intergiciel comme filtre, créez un type avec une méthode Configure qui spécifie l’intergiciel que vous voulez injecter dans le pipeline de filtres.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. Voici un exemple qui utilise l’intergiciel de localisation pour établir la culture d’une requête :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);
    }
}

Vous pouvez ensuite utiliser MiddlewareFilterAttribute pour exécuter l’intergiciel pour un contrôleur ou une action sélectionnés, ou globalement :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}");
}

Les filtres d’intergiciels s’exécutent à la même étape du pipeline de filtres en tant que filtres de ressources, avant la liaison de modèle et après le reste du 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.

Actions suivantesNext actions

Pour expérimenter les filtres, téléchargez, testez et modifiez l’exemple.To experiment with filters, download, test and modify the sample.