2009-05-13 13 views
5

Gibt es eine Möglichkeit, ein Attribut auf der Controller-Ebene hinzuzufügen, aber nicht auf einer bestimmten Aktion. Sagen wir zum Beispiel, wenn ich 10 Aktionen in meinem Controller hatte und nur eine dieser Aktionen kein spezifisches Attribut benötigt, das ich erstellt habe.MVC-Attribute für Controller und Aktionen

 
[MyAttribute] 
public class MyController : Controller 
{ 
    public ActionResult Action1() {} 
    public ActionResult Action2() {} 

    [Remove_MyAttribute] 
    public ActionResult Action3() {} 
} 

ich möglicherweise diese Aktion in einem anderen Controller bewegen konnte (aber nicht so) oder ich könnte die MyAttribute auf alle Aktionen außer von Action3 gelten aber nur gedacht, wenn es einen einfacheren Weg?

Antwort

3

Johannes gab die richtige Lösung und hier ist, wie ich es codiert ... hoffe, es hilft anderen Menschen.

 
[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; 

     ... 
    } 
+0

Danke David! Genau was ich vorhatte! –

2

Sie eine bestimmte Aktion an dem Haupt-Attribut ausschließen könnte, indem man:

[MyAttribute(Exclude="Action3")] 

EDIT

Mein Beispiel vom Kopf war (wie Sie die folgende ist VB.NET sehen können, vielleicht ist das der Punkt, wo es schief gelaufen ist), so habe ich implementiert:

<Models.MyAttribute(Exclude:="Action3")> _ 
Public Class MyController 
Inherits System.Web.Mvc.Controller 

End Class 
3

Sie müssen das Standardattribut überschreiben/erweitern und eine benutzerdefinierte Con hinzufügen structor, um den Ausschluss zuzulassen. Oder Sie können Ihr benutzerdefiniertes Attribut für den Ausschluss erstellen (in Ihrem Beispiel ist das [Remove_MyAttribute]).

+0

danke für den Punkt in die richtige Richtung. Ive upoted Ihre Antwort dann lieferte die Lösung in meiner Antwort unten. – David

2

Das übliche Muster für das, was Sie zu tun versuchen, ist mit einem boolean Parameter zu haben, und Attribute, das das Attribut gibt an, ob angewandt wird oder nicht.

Ex:

[ComVisible] which is equivalent with [ComVisible(true)] 

or 

[ComVisible(false)] 

Ihren Fall inf würden Sie haben:

[MyAttribute] // defaults to true 

and 

[MyAttribute(false)] for applying the attribute on excluded members 
+0

Also definieren Sie es auf der Controller-Ebene, dann überschreiben Sie es effektiv auf der Aktion selbst ... Ich mag diese Idee und ist einfacher als den Vergleich mit Action-Namen. Danke für deine Lösung. – David

+0

Ich benutze RenderAction von einer Hilfsmethode, auf der das MyAttribute (false) definiert ist, aber wenn ich debugge, obwohl es den richtigen Konstruktor aufruft, wird die private Variable in meinem Attribut immer zurückgesetzt. Irgendwelche Ideen? – David

3

Ich weiß, dass meine Antwort ein wenig zu spät ist (fast vier Jahre), um das Spiel, aber ich kam in dieser Frage und ich wollte eine Lösung teilen, die ich mir ausgedacht habe und die mir erlaubt, ziemlich genau das zu tun, was die ursprüngliche Frage machen wollte, falls es jemand anderem in der Zukunft hilft.

Die Lösung beinhaltet ein kleines Juwel namens AttributeUsage, mit dem wir ein Attribut auf dem Controller (und sogar jedem Basiscontroller!) Angeben und dann bei einzelnen Aktionen oder Subcontrollern nach Bedarf überschreiben (ignorieren/entfernen) können. Sie "kaskadieren" bis zu dem Punkt, an dem nur das granularste Attribut tatsächlich ausgelöst wird: d. H., Sie gehen von den am wenigsten spezifischen (Basis-Controllern) zu spezifischeren (abgeleiteten Controllern) zu den meisten spezifischen (Aktionsmethoden).

Hier ist, wie:

[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 
} 

(ich Sie wie Attribute gehört, so habe ich einige Attribute auf das Attribut, das ist wirklich, was die magische Arbeit hier an der Spitze macht: Erlauben sie/Kaskade zu erben, aber nur einer von ihnen erlaubt auszuführen)

Hier ist, wie es jetzt verwendet wird.

[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... 

} 

ich hoffe, das kompiliert, ich riss es aus einem ähnlichen Code und habe ein wenig s suche und ersetze es, damit es nicht perfekt ist.

+0

PS, der Vorteil bei dieser Methode, die ich vergessen habe explizit zu erwähnen, ist, dass Sie keine magischen Strings haben, die Action-Namen darstellen, noch müssen Sie daran denken, das Mapping oben auf dem neuesten Stand zu halten : Du dekorierst einfach, während du gehst und den Ignore/Respect-Schalter nach Bedarf hin und her schiebst, je weiter du nach unten gehst. Viel Glück! – Funka

+0

Für die Nachwelt: Siehe auch http://stackoverflow.com/questions/4390541/asp-net-mvc-ignore-custom-attribute-in-a-base-controller-class/5070193#5070193 – Funka

Verwandte Themen