9

Ich versuche, eine ActionDescriptor für eine Aktion auf einem Controller, der Attribut Routing verwendet, aber es ist immer Null.Wie bekomme ich den ActionDescriptor eines Mvc 5 Controllers, wenn ich Attribute Routing verwende?

var controllerDescriptor = new ReflectedControllerDescriptor(controllerType); 
var actionDescriptor = 
    controllerDescriptor.FindAction(controllerContext, actionName) ?? 
    controllerDescriptor.GetCanonicalActions().FirstOrDefault(a => a.ActionName == actionName); 

Aus meiner Forschung habe ich, dass ActionMethodSelectorBase in der Klasse gefunden gibt es ein Verfahren PopulateLookupTables die aufspaltet alle Methoden in der Steuerung, die Sie geben genannt wird. Innerhalb dieser Methode filtert es die Liste der MethodInfo's in 2 Gruppen von Listen.

  • AliasedMethods - Alle Aktionsmethoden ohne direkte Routen, die mit dem ActionNameSelectorAttribute verziert sind.
  • NonAliasedMethods - Alle Aktionsmethoden ohne direkte Routen, die mit dem ActionNameSelectorAttribute nicht eingerichtet sind.

HINWEIS: Die AliasedMethods und NonAliasedMethods werden leer sein, wenn eine direkte Route (RouteAttribute) auf Controller-Ebene eingestellt ist.

HINWEIS: direkte Wege sind als Verfahren definiert, das in einem Controller (ohne Konstruktoren und Ereignisse) sind und mit einem Attribut versehen, die entweder aus oder IRouteInfoProvider IDirectRouteFactory erbt (RouteAttribute von diesen beiden erbt).

und

  • DirectRouteMethods - Methoden mit irgendeiner Form von IRouteInfoProvider sie direkt zu dekorieren.
  • StandardRouteMethods - Methoden ohne IRouteInfoProvider, die sie direkt verzieren. (Enthält Aktionsmethoden in einem Controller mit RouteAttribute, für die die Methode jedoch kein RouteAttribute enthält).

Wenn ReflectedControllerDescriptor.FindAction aufgerufen wird, intern nennt es ActionMethodSelectorBase.FindActionMethods, die nur an den AliasedMethods und NonAliasedMethods sieht (die alle Aktionen mit direktem Wege ausschließen).

Wenn ReflectedControllerDescriptor.GetCanonicalActions aufgerufen wird, intern nennt es ReflectedControllerDescriptor.GetAllActionMethodsFromSelector, die nur an den AliasedMethods sieht und NonAliasedMethods (die alle Aktionen mit direkten Routen exlude).

Von dem, was ich sehen kann, die DirectRouteMethods nur an einem Ort verwendet werden, die RouteCollection.MapMvcAttributeRoutes Erweiterung Methoden. Dies bedeutet, dass die RouteTable.Routen Sammlung hat eine RouteCollectionRoute auf die Aktion, aber ich bin mir nicht sicher, wie man dazu kommt.

Weiß jemand, wie ein ActionDescriptor für eine Aktion zu erhalten, die eine RouteAttribute hat

Antwort

1

können Sie die AsyncControllerActionInvoker Klasse verwenden, um dies zu tun, aber da die Methode, die Sie müssen geschützt ist, müssen Sie zuerst erben Sie die Klasse und definieren Sie die Methode als public neu.

private class ActionSelector 
    : AsyncControllerActionInvoker 
{ 
    // Needed because FindAction is protected, and we are changing it to be public 
    public new ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) 
    { 
     return base.FindAction(controllerContext, controllerDescriptor, actionName); 
    } 
} 

Dann ist es nur eine Frage der Verwendung der gleichen 2 Objekte, die Sie zuvor hatten, um die neue Methode aufzurufen.

var controllerDescriptor = new ReflectedControllerDescriptor(controllerType); 
var actionSelector = new ActionSelector(); 
var actionDescriptor = 
    actionSelector.FindAction(controllerContext, controllerDescriptor, actionName) ?? 
    controllerDescriptor.GetCanonicalActions().FirstOrDefault(a => a.ActionName == actionName); 

Beachten Sie, dass dies sowohl für StandardRouteMethods als auch für DirectRouteMethods funktioniert.

Es ist jedoch eine Sache zu beachten, dass das Aufrufen dieser Methode die RouteData für die Eigenschaften controllerContext.RouteData und controllerContext.RequestContext.RouteData auf die der Aktion zurückgesetzt, die gefunden wird. Daher müssen Sie die ControllerContext- und RequestContext-Klassen umbrechen und die RouteData-Eigenschaften neu implementieren, damit der Setter keine Auswirkungen hat, wenn es wichtig ist, dass Sie den Kontext nicht zerstören.

Referenz: https://aspnetwebstack.codeplex.com/workitem/1989