2009-11-27 34 views
54

Si creo un objeto en un filtro de acciones personalizadas en ASP.NET MVC enASP.NET MVC Pass objeto de acción personalizada Filtro de Acción

public override void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    DetachedCriteria criteria = DetachedCriteria.For<Person>(); 
    criteria.Add("stuff"); 

    // Now I need to access 'criteria' from the Action..... 

} 

¿hay alguna manera de que pueda acceder el objeto de la acción que se está ejecutando actualmente.

Respuesta

43

recomendaría ponerlo en los datos de ruta.

protected override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.RouteData.Values.Add("test", "TESTING"); 
     base.OnActionExecuting(filterContext); 
    } 

    public ActionResult Index() 
    { 
     ViewData["Message"] = RouteData.Values["test"]; 

     return View(); 
    } 
+2

¿Cuánto tiempo sobrevive un elemento en RouteData? Solo necesito mantener el objeto durante la acción que se está ejecutando actualmente, o como mucho para la solicitud actual, si así es como funcionan los datos de la ruta, entonces esta es la respuesta; de lo contrario, HttpContext.Items es probablemente mejor. – reach4thelasers

+1

RouteData es datos relacionados con la ruta (acción) actualmente en ejecución. Piénselo como un contenedor que representa la url de solicitud analizada y mapeada de acuerdo con sus reglas de enrutamiento. – Neal

+0

'RouteData' es ciertamente genial para hacer esto, como he aprendido hoy gracias a su respuesta aquí. Mi hermoso libro negro y amarillo MVC aquí en frente de mí (cuarta edición) no menciona nada al respecto ni hace nada similar a esto en todo el capítulo sobre filtros (¿o al menos no lo he encontrado aún?) De todos modos, +1 y ¡gracias! – Funka

30

Se podría utilizar el HttpContext:

filterContext.HttpContext.Items["criteria"] = criteria; 

Y se puede leer en la acción:

[YourActionFilter] 
public ActionResult SomeAction() 
{ 
    var criteria = HttpContext.Items["criteria"] as DetachedCriteria; 
} 
+1

Estaba pensando acerca del uso de HttpContext.Items [] y su una solución aceptable, ya que se borrará al final de la solicitud. No estaba seguro de si había un lugar donde pudiera almacenar cosas que solo existe mientras dure la acción. – reach4thelasers

3

elemento situado en ViewData o de un modelo de vista si se le pasa como parámetro en su acción. Aquí establezca la propiedad de un modelo de vista

public override void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    ViewModelBase viewModel = null; 
    foreach (object parameter in filterContext.ActionParameters.Values) 
    { 
     if (parameter is ViewModelBase) 
     { 
      viewModel = (ViewModelBase)parameter; 
      break; 
     } 
    } 
    if(viewModel !=null) 
    { 
     viewModel.SomeProperty = "SomeValue"; 
    } 
} 


    public ActionResult About(ViewModelBase model) 
    { 
     string someProperty= model.SomeProperty; 
} 

Aquí está la versión sin tipo Creo que prefiera:

public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.Controller.ViewData.Add("TestValue", "test"); 

    } 

     [FilterWhichSetsValue] 
     public ActionResult About() 
     { 
      string test = (string)ViewData["TestValue"]; 
      return View(); 
     } 
+0

Gracias por su sugerencia. Sin embargo, mis acciones no toman ViewModelBase como parámetro, y preferiría no presentarlo solo para resolver mi problema. – reach4thelasers

+0

Consulte la publicación editada de la versión sin tipo. Todavía usaría la primera versión. Tal vez el nombre del parámetro suena mal. Puede ser cualquier clase y no tiene que ser la clase de la vista mecanografiada. –

59

El better approach se describe por Phil Haack.

Básicamente esto es lo que hace:

public class AddActionParameterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     base.OnActionExecuting(filterContext); 

     // Create integer parameter. 
     filterContext.ActionParameters["number"] = 123; 

     // Create object parameter. 
     filterContext.ActionParameters["person"] = new Person("John", "Smith"); 
    } 
} 

El gotcha es que si va a crear los parámetros del objeto, entonces su clase (en este caso la persona) debe tener un constructor por defecto, de lo contrario obtendrá una excepción.

Así es como tendrá que utilizar el filtro anterior:

[AddActionParameter] 
public ActionResult Index(int number, Person person) 
{ 
    // Now you can use number and person variables. 
    return View(); 
} 
+1

Muy buena manera de hacer esto, definitivamente creo que esto es mucho mejor que la respuesta aceptada. ¡Esta debería ser la respuesta aceptada! ¡Gracias! – avb

+0

¿Por qué es esto mejor que la respuesta aceptada?No parece haber ninguna razón por la cual este sea el caso y el [AddActionParameter] adicional es claramente un trabajo adicional que el otro método no requiere para funcionar. –

+0

@ChrisBertrand Es más limpio y evita errores en el tiempo de compilación en el controlador, mediante el uso de tipo fuerte, es decir, la clase 'Persona'. También hace que las pruebas unitarias sean mucho más fáciles. – niaher

Cuestiones relacionadas