2009-05-13 19 views
5

Hay una manera de agregar un atributo en el nivel del controlador pero no en una acción específica. Por ejemplo, decir si tenía 10 acciones en mi controlador y solo una de esas acciones no requiere un atributo específico que creé.Atributos de MVC en controladores y acciones

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

    [Remove_MyAttribute] 
    public ActionResult Action3() {} 
} 

que podía potencialmente mover esta acción en otro controlador (pero no te gusta eso) o podría aplicar el MyAttribute a todas las acciones excepto de Action3 pero sólo pensado si hay una manera más fácil?

Respuesta

3

Johannes dio la solución correcta y así es como lo codifiqué ... espero que ayude a otras personas.

 
[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

Gracias David! ¡Exactamente lo que tenía en mente! –

2

Se podía excluir una acción específica pasándolo al atributo principal:

[MyAttribute(Exclude="Action3")] 

EDITAR

Mi ejemplo fue de la cabeza (como se puede ver lo que sigue es VB.NET, tal vez eso es lo que salió mal), así es como lo implementé:

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

End Class 
3

Tiene que anular/extender el atributo predeterminado y agregar una configuración personalizada Instructor para permitir la exclusión. O puede crear su atributo personalizado para la exclusión (en su ejemplo es [Remove_MyAttribute]).

+0

gracias por el punto en la dirección correcta. He votado a favor su respuesta y luego proporcioné la solución en mi respuesta a continuación. – David

2

El patrón habitual de lo que está tratando de hacer es tener y atributo con un parámetro booleano que indica si se aplica o no el atributo.

Ex:

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

or 

[ComVisible(false)] 

inf su caso, tendría que:

[MyAttribute] // defaults to true 

and 

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

Así que lo define en el nivel del Controlador y lo anula en la Acción en sí ... me gusta esa idea y es más simple que compararla con los nombres de las acciones. gracias por tu solución – David

+0

Estoy usando RenderAction de un método de ayuda que define MyAttribute (falso), sin embargo, cuando depuro aunque llama al constructor correcto, la variable privada dentro de mi atributo sigue siendo restablecida. ¿Algunas ideas? – David

3

sé que mi respuesta es un poco tarde (casi cuatro años) para el juego, pero me encontré con esta pregunta y quería compartir una solución que ideé que me permite hacer más o menos lo que la pregunta original quería hacer, en caso de que ayude a alguien más en el futuro.

La solución consiste en una pequeña gema llamada AttributeUsage, que nos permite especificar un atributo en el controlador (¡e incluso cualquier controlador base!) Y luego anular (ignorar/eliminar) en acciones individuales o subcontroladores según sea necesario. Se "conectarán en cascada" hasta donde solo se dispara el atributo más granular: es decir, pasan de ser menos específicos (controladores de base) a más específicos (controladores derivados), a los más específicos (métodos de acción).

Así es como:

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

(he oído como atributos, por lo que poner algunos atributos en el atributo Eso es realmente lo que hace que el trabajo de magia aquí en lo más alto:! Lo que les permite heredar/cascada, pero sólo uno de ellos lo que permite ejecutar)

Así es como se usa ahora:.

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

} 

espero que esto compila, di un tirón desde algún código similar y hice un poco de s earch-and-replace en él así que puede no ser perfecto.

+0

PD, la ventaja de este enfoque en mi opinión, que me olvidé de indicar explícitamente, es que no tienes cadenas mágicas que representen nombres de acción, ni necesitas recordar mantener el mapeo actualizado en la parte superior de todo : simplemente decora sobre la marcha, activando el interruptor Ignorar/Respetar hacia adelante y hacia atrás según sea necesario cuanto más abajo vaya. ¡Buena suerte! – Funka

+0

Para la posteridad: Vea también http://stackoverflow.com/questions/4390541/asp-net-mvc-ignore-custom-attribute-in-a-base-controller-class/5070193#5070193 – Funka

Cuestiones relacionadas