Reputation: 15360
Is there a way to add an Attribute on the Controller level but not on a specific action. For example say if i had 10 Actions in my Controller and just 1 of those Actions does not require a specific attribute I created.
[MyAttribute] public class MyController : Controller { public ActionResult Action1() {} public ActionResult Action2() {} [Remove_MyAttribute] public ActionResult Action3() {} }
I could potentially move this Action into another controller (but dont like that) or I could apply the MyAttribute to all actions except from Action3 but just thought if there is an easier way?
Upvotes: 8
Views: 18717
Reputation: 2077
You have to override/extend the default attribute and add a custom constructor to allow exclusion. Or you can create your custom attribute for exclusion (in your example is the [Remove_MyAttribute]
).
Upvotes: 4
Reputation: 4278
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.
Upvotes: 9
Reputation: 62990
The usual pattern for what you are trying to do is to have and attribute with a boolean parameter that indicates if the attribute is applied or not.
Ex:
[ComVisible] which is equivalent with [ComVisible(true)]
or
[ComVisible(false)]
inf your case you would have:
[MyAttribute] // defaults to true
and
[MyAttribute(false)] for applying the attribute on excluded members
Upvotes: 2
Reputation: 17804
You could exclude a specific action by passing it to the main attribute:
[MyAttribute(Exclude="Action3")]
EDIT
My example was from the head (as you can see the following is VB.NET, maybe that's where it went wrong), this is how I implemented:
<Models.MyAttribute(Exclude:="Action3")> _
Public Class MyController
Inherits System.Web.Mvc.Controller
End Class
Upvotes: 2
Reputation: 15360
Johannes gave the correct solution and here is how I coded it... hope it helps other people.
[MyFilter("MyAction")] public class HomeController : Controller { public ActionResult Action1... public ActionResult Action2... public ActionResult MyAction... } public class CompressFilter : ActionFilterAttribute { private IList _ExcludeActions = null; public CompressFilter() { _ExcludeActions = new List(); } public CompressFilter(string excludeActions) { _ExcludeActions = new List(excludeActions.Split(',')); } public override void OnActionExecuting(ActionExecutingContext filterContext) { HttpRequestBase request = filterContext.HttpContext.Request; string currentActionName = (string)filterContext.RouteData.Values["action"]; if (_ExcludeActions.Contains(currentActionName)) return; ... }
Upvotes: 3