JeremyWeir
JeremyWeir

Reputation: 24368

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

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.

Upvotes: 7

Views: 3513

Answers (2)

samy
samy

Reputation: 14962

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.

Upvotes: 3

robertz
robertz

Reputation: 778

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

Upvotes: 11

Related Questions