web-dev-qa-db-fra.com

Exécuter le filtre global avant OnActionExecuting du contrôleur, dans ASP.NET Core

Dans une application ASP.NET Core 2.0, j'essaie d'exécuter le OnActionExecuting d'un filtre global avant d'exécuter la variante du contrôleur. Le comportement attendu est que je peux préparer quelque chose dans le global avant et transmettre la valeur du résultat au (x) contrôleur (s). Cependant, le comportement actuel est que l'ordre d'exécution est inversé par conception.

Les documents me parlent de ordre d'exécution par défaut :

Chaque contrôleur qui hérite de la classe de base Controller inclut les méthodes OnActionExecuting et OnActionExecuted. Ces méthodes encapsulent les filtres qui s'exécutent pour une action donnée: OnActionExecuting est appelé avant l'un des filtres et OnActionExecuted est appelé après tous les filtres.

Ce qui m'amène à interpréter que le OnActionExecuting du contrôleur est exécuté avant l'un des filtres. Logique. Mais la documentation indique également que l'ordre par défaut peut être remplacé en implémentant IOrderedFilter.

Ma tentative d'implémenter cela dans un filtre est comme suit:

public class FooActionFilter : IActionFilter, IOrderedFilter
{
    // Setting the order to 0, using IOrderedFilter, to attempt executing
    // this filter *before* the BaseController's OnActionExecuting.
    public int Order => 0;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // removed logic for brevity
        var foo = "bar";

        // Pass the extracted value back to the controller
        context.RouteData.Values.Add("foo", foo);
    }
}

Ce filtre est enregistré au démarrage comme:

services.AddMvc(options => options.Filters.Add(new FooActionFilter()));

Enfin, mon BaseController ressemble à l'exemple ci-dessous. Cela explique le mieux ce que j'essaie de réaliser:

public class BaseController : Controller
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // The problem: this gets executed *before* the global filter.
        // I actually want the FooActionFilter to prepare this value for me.
        var foo = context.RouteData.Values.GetValueOrDefault("foo").ToString();
    }
}

La définition de Order sur 0, ou même une valeur non nulle comme -1, ne semble pas avoir d'effet sur l'ordre d'exécution.

Ma question: que puis-je faire pour que mon filtre global exécute le OnActionExecuting avant le contrôleur (de base) OnActionExecuting ?

14
Juliën

Tu y es presque. Votre petite erreur est que l'ordre par défaut de l'exécution du filtre du contrôleur n'est pas 0. Cet ordre est défini dans la classe ControllerActionFilter comme int.MinValue ( code source ):

public class ControllerActionFilter : IAsyncActionFilter, IOrderedFilter
{
    // Controller-filter methods run farthest from the action by default.
    /// <inheritdoc />
    public int Order { get; set; } = int.MinValue;

    // ...
}

Par conséquent, la seule modification que vous devez apporter à votre code actuel consiste à définir FooActionFilter.Order à int.MinValue:

public class FooActionFilter : IActionFilter, IOrderedFilter
{
    public int Order => int.MinValue;

    //  ...
}

Maintenant, FooActionFilter et ControllerActionFilter ont le même ordre. Mais FooActionFilter est un filtre global, tandis que ControllerActionFilter est un filtre de niveau contrôleur. C'est pourquoi FooActionFilter sera exécuté le premier, basé sur cette instruction :

La propriété Order l'emporte sur la portée lors de la détermination de l'ordre dans lequel les filtres s'exécuteront. Les filtres sont d'abord triés par ordre, puis la portée est utilisée pour rompre les liens .

9
CodeFuller