I know my answer is a little late (almost four years) to the game, but I came across this question and wanted to share a solution I devised that allows me to do pretty much what the original question wanted to do, in case it helps anyone else in the future.
The solution involves a little gem called AttributeUsage
, which allows us to specify an attribute on the controller (and even any base controllers!) and then override (ignore/remove) on individual actions or sub-controllers as needed. They will "cascade" down to where only the most granular attribute actually fires: i.e., they go from least-specific (base controllers), to more-specific (derived controllers), to most-specific (action methods).
Here's how:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomFilterAttribute : ActionFilterAttribute
{
private MyCustomFilterMode _Mode = MyCustomFilterMode.Respect; // this is the default, so don't always have to specify
public MyCustomFilterAttribute()
{
}
public MyCustomFilterAttribute(MyCustomFilterMode mode)
{
_Mode = mode;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (_Mode == MyCustomFilterMode.Ignore)
{
return;
}
// Otherwise, respect the attribute and work your magic here!
//
//
//
}
}
public enum MyCustomFilterMode
{
Ignore = 0,
Respect = 1
}
(I heard you like attributes, so I put some attributes on the attribute! That's really what makes the magic work here at the very top: Allowing them to inherit/cascade, but only allowing one of them to execute.)
Here's how it is used now:
[MyCustomFilter]
public class MyBaseController : Controller
{
// I am the application's base controller with the filter,
// so any derived controllers will ALSO get the filter (unless they override/Ignore)
}
public class HomeController : MyBaseController
{
// Since I derive from MyBaseController,
// all of my action methods will also get the filter,
// unless they specify otherwise!
public ActionResult FilteredAction1...
public ActionResult FilteredAction2...
[MyCustomFilter(Ignore)]
public ActionResult MyIgnoredAction... // I am ignoring the filter!
}
[MyCustomFilter(Ignore)]
public class SomeSpecialCaseController : MyBaseController
{
// Even though I also derive from MyBaseController, I can choose
// to "opt out" and indicate for everything to be ignored
public ActionResult IgnoredAction1...
public ActionResult IgnoredAction2...
// Whoops! I guess I do need the filter on just one little method here:
[MyCustomFilter]
public ActionResult FilteredAction1...
}
I hope this compiles, I yanked it from some similar code and did a little search-and-replace on it so it may not be perfect.