2009-11-27 6 views
54

Wenn ich ein Objekt in einem benutzerdefinierten Aktion Filter in ASP.NET MVC inASP.NET MVC Pass Objekt von benutzerdefinierten Aktion zu Aktion filtern

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

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

} 

schaffen, ist es eine Möglichkeit, das Objekt von der Aktion zugreifen können das gerade ausgeführt wird.

Antwort

43

ich empfehlen würde es in den Routendaten setzen.

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

Wie lange hält ein Gegenstand in RouteData? Ich muss nur das Objekt für die Dauer der gerade ausgeführten Aktion oder höchstens für die aktuelle Anfrage behalten, wenn so die Routendaten funktionieren, dann ist dies die Antwort, ansonsten ist HttpContext.Items wahrscheinlich besser. – reach4thelasers

+1

RouteData sind Daten, die sich auf die aktuell ausgeführte Route (Aktion) beziehen. Stellen Sie es sich als einen Container vor, der die angeforderte URL darstellt, die gemäß Ihren Routingregeln analysiert und zugeordnet wurde. – Neal

+0

"RouteData" ist sicherlich großartig, um dies zu tun, wie ich heute dank Ihrer Antwort hier gelernt habe. Mein schönes schwarz-gelbes MVC-Buch hier vor mir (vierte Auflage) erwähnt nichts davon oder macht gar nichts Ähnliches im gesamten Filterkapitel (zumindest habe ich es noch nicht gefunden?). Wie auch immer, +1 und danke! – Funka

30

könnten Sie verwenden die HttpContext:

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

Und Sie können es in der Aktion zu lesen:

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

Ich dachte über die Verwendung von HttpContext.Items [] und seine eine akzeptable Lösung, da es am Ende des Antrags wird ausgeräumt werden. Ich war mir nicht sicher, ob es einen Ort gab, wo ich Sachen aufbewahren konnte, die nur für die Dauer der Aktion existierten. – reach4thelasers

3

Set Artikel in Bildschirmtextsystem oder einer Ansichtsmodell, wenn Sie es als Parameter in Ihren Pass Aktion. Hier stelle ich die Eigenschaft einer Ansichtsmodell

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

Hier ist die nicht typisierte Version Ich glaube, Sie bevorzugen:

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

    } 

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

Danke für Ihren Vorschlag. Meine Aktionen verwenden ViewModelBase jedoch nicht als Parameter, und ich würde es vorziehen, sie nicht nur zur Lösung meines Problems einzuführen. – reach4thelasers

+0

Siehe den bearbeiteten Post für die untypisierte Version. Ich würde immer noch die erste Version verwenden. Vielleicht klingt der Parametername einfach zu schlecht. Es kann jede Klasse sein und muss nicht die Klasse der typisierten Ansicht sein. –

59

Die better approach wird von Phil Haack beschrieben.

Im Grunde ist es das, was Sie tun können:

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"); 
    } 
} 

Der einzige gotcha ist, dass, wenn Sie Objektparameter erstellen, dann die Klasse (in diesem Fall Person) einen Standardkonstruktor haben muss, sonst werden Sie eine bekommen Ausnahme.

Hier ist, wie Sie den oben genannten Filter verwenden würden:

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

Sehr schöne Möglichkeit, dies zu tun, ich denke auf jeden Fall ist das viel besser als die angenommene Antwort. Dies sollte die akzeptierte Antwort sein! Vielen Dank! – avb

+0

Warum ist das besser als die angenommene Antwort?Es scheint keinen Grund zu geben, warum dies der Fall wäre und der zusätzliche [AddActionParameter] ist eindeutig zusätzliche Arbeit, die die andere Methode nicht benötigt. –

+0

@ChrisBertrand Es ist sauberer und vermeidet Fehler bei der Kompilierung in der Steuerung, indem man die stark typisierende, dh "Person" -Klasse verwendet. Es erleichtert auch das Testen von Einheiten erheblich. – niaher