2009-05-13 16 views
5

C'è un modo per aggiungere un attributo a livello di controller ma non su un'azione specifica. Ad esempio, supponiamo di avere 10 azioni nel mio controller e solo una di quelle azioni non richiede un attributo specifico che ho creato.Attributi MVC su controller e azioni

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

    [Remove_MyAttribute] 
    public ActionResult Action3() {} 
} 

ho potuto potenzialmente spostare questo azione in un altro controller (ma non lo simile) oppure avrei potuto applicare il MyAttribute a tutte le azioni tranne dal Action3 ma solo pensato se c'è un modo più semplice?

risposta

3

Johannes ha fornito la soluzione corretta ed ecco come l'ho codificato ... spero che aiuti gli altri.

 
[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

Grazie David! Esattamente quello che avevo in mente! –

2

Si potrebbe escludere un'azione specifica per passarlo al principale attributo:

[MyAttribute(Exclude="Action3")] 

EDIT

Il mio esempio era dalla testa (come si può vedere il seguente è VB.NET, forse è lì che è andata male), questo è come ho implementato:

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

End Class 
3

Devi eseguire l'override/estendo l'attributo di default e aggiungi un con personalizzato strutturatore per consentire l'esclusione. Oppure puoi creare il tuo attributo personalizzato per l'esclusione (nel tuo esempio è [Remove_MyAttribute]).

+0

grazie per il punto nella giusta direzione. Ho alzato la tua risposta e ho fornito la soluzione nella mia risposta qui sotto. – David

2

Lo schema usuale per ciò che si sta cercando di fare è di avere e di attribuire con un parametro booleano che indica se l'attributo viene applicato o meno.

Es:

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

or 

[ComVisible(false)] 

inf vostro caso si avrebbe:

[MyAttribute] // defaults to true 

and 

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

Così lo si definisce a livello di Controller, quindi lo si sovrascrive effettivamente sull'azione stessa ... mi piace l'idea ed è più semplice rispetto al confronto con i nomi delle azioni. grazie per la tua soluzione – David

+0

Sto usando RenderAction da un metodo Helper su cui è definito MyAttribute (false), tuttavia quando eseguo il debug nonostante chiami il costruttore corretto, la variabile privata all'interno del mio attributo continua a essere ripristinata. Qualche idea? – David

3

So che la mia risposta è un po 'tardi (quasi quattro anni) per il gioco, ma mi sono imbattuto in questa domanda e volevo condividere una soluzione che ho ideato che mi permettesse di fare più o meno quello che la domanda originale voleva fare, nel caso in cui aiutasse qualcun altro in futuro.

La soluzione comprende un piccolo gioiello chiamato AttributeUsage, che ci consente di specificare un attributo sul controller (e anche su qualsiasi controller di base! Essi "si sovrappongono" fino a dove viene attivato solo l'attributo più granulare: cioè, passano da meno specifici (controllori di base) a più specifici (controllori derivati), a più specifici (metodi di azione).

Ecco come:

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

(ti ho sentito come attributi, così ho messo alcuni attributi per l'attributo Questo è davvero ciò che rende il lavoro magia qui in cima: permettendo loro di ereditare/a cascata, ma consentendo solo uno di loro da eseguire)

Ecco come viene utilizzato oggi:.

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

} 

Spero che questo compila, mi strappai da qualche codice simile e ha fatto un po 'di s earch-and-replace su di esso in modo che potrebbe non essere perfetto.

+0

PS, il vantaggio con questo approccio a mio avviso, che ho dimenticato di dichiarare esplicitamente, è che non hai stringhe magiche che rappresentano nomi di azioni, né devi ricordare di mantenere aggiornata la mappatura nella parte superiore di tutto : decorerai semplicemente mentre vai, spostando l'interruttore Ignora/Rispetta avanti e indietro, secondo necessità, più in basso. In bocca al lupo! – Funka

+0

Per i posteri: vedere anche http://stackoverflow.com/questions/4390541/asp-net-mvc-ignore-custom-attribute-in-a-base-controller-class/5070193#5070193 – Funka

Problemi correlati