Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make ActionFilter on action method take precedence over same ActionFilter on controller

Tags:

asp.net-mvc

Since asp.net mvc has changed a lot since November, does anyone have a solution to this question:

Resolve FilterAttributes On Controller And Action

Phil said an ActionFilter on a controller is just shorthand for applying the attribute to all action methods of the controller, and it is true, if I put the same ActionFilter attribute on the controller and on an action method, it will run twice. But this doesn't seem like natural behavior since the compiler won't even let you put the same attribute directly on a method multiple times.

like image 840
JeremyWeir Avatar asked May 29 '09 19:05

JeremyWeir


2 Answers

A filter can take precedence over another filter by specifing the Order property on each filter. For example...

[MyFilter(Order=2)]
public class MyController : Controller
{
    [MyFilter(Order=1)]
    public ActionResult MyAction()
    {
        //...
    }
}

In this example the filter on the action method would execute before the filer on the controller.

HTH

like image 101
robertz Avatar answered Sep 18 '22 01:09

robertz


I found one way to do it by "cheating" a bit with the ordering, inheritance and the AttributeUsage parameter

First, define your ActionFilter for the controller

[AttributeUsage(AttributeTargets.Class)]
public class FilterController : ActionFilterAttribute
{
    public FilterController()
    {
        this.Order = 2;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (!filterContext.HttpContext.Items.Contains("WeAlreadyWentThroughThis"))
        {
                // do our thing
            filterContext.HttpContext.Items.Add("WeAlreadyWentThroughThis", "yep");
            base.OnActionExecuted(filterContext);
        }
    }
}

Then inherit the class for your action attribute

[AttributeUsage(AttributeTargets.Method)]
public class FilterAction : FilterController
{
    public FilterAction()
    {
        this.Order = 1;
    }
}

It's far from perfect since you have to rely on HttpContext and two classes (though you could use namespaces to name both classes the same). But you get compiler-enforced check of the attribute scope for class or action and you won't forget an order parameter when typing the code.

like image 38
samy Avatar answered Sep 20 '22 01:09

samy