【问题标题】:How do I get an Mvc 5 Controller's ActionDescriptor when using Attribute Routing?使用属性路由时如何获取 Mvc 5 控制器的 ActionDescriptor?
【发布时间】:2014-04-03 23:16:54
【问题描述】:

我正在尝试为使用 Attribute Routing 的控制器上的操作获取 ActionDescriptor,但它始终为 null。

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

根据我的研究,我发现在 ActionMethodSelectorBase 类中有一个名为 PopulateLookupTables 的方法,它将您提供给它的控制器中的所有方法分开。在该方法内部,它将 MethodInfo 列表过滤为 2 组列表。

  • AliasedMethods - 所有没有直接路由且使用 ActionNameSelectorAttribute 修饰的操作方法。
  • NonAliasedMethods - 所有没有直接路由且未使用 ActionNameSelectorAttribute 修饰的操作方法。

注意:如果在控制器级别设置了直接路由 (RouteAttribute),则 AliasedMethods 和 NonAliasedMethods 将为空。

注意:直接路由定义为控制器中的方法(不包括构造函数和事件),并使用从 IRouteInfoProvider 或 IDirectRouteFactory 继承的属性进行装饰(RouteAttribute 继承自这两者)。

  • DirectRouteMethods - 使用某种形式的 IRouteInfoProvider 直接装饰它们的方法。
  • StandardRouteMethods - 没有 IRouteInfoProvider 直接装饰它们的方法。 (包括具有 RouteAttribute 但该方法没有 RouteAttribute 的控制器中的操作方法。

ReflectedControllerDescriptor.FindAction 被调用时,它在内部调用 ActionMethodSelectorBase.FindActionMethods 只查看 AliasedMethodsNonAliasedMethods strong>(排除所有直接路由的操作)。

ReflectedControllerDescriptor.GetCanonicalActions 被调用时,它在内部调用 ReflectedControllerDescriptor.GetAllActionMethodsFromSelector 只查看 AliasedMethodsNonAliasedMethods strong>(排除所有直接路由的操作)。

据我所知,DirectRouteMethods 只用在一个地方,RouteCollection.MapMvcAttributeRoutes 扩展方法。这意味着 RouteTable.Routes 集合有一个 RouteCollectionRoute 到操作,但我不知道如何到达它。

有谁知道如何为具有 RouteAttribute

的操作获取 ActionDescriptor

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-routing asp.net-mvc-5 attributerouting


    【解决方案1】:

    你可以使用 AsyncControllerActionInvoker 类来做到这一点,但是由于你需要的方法是受保护的,你需要先继承该类并将该方法重新定义为 public。

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

    那么只需使用与之前相同的 2 个对象来调用新方法。

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

    请注意,这适用于 StandardRouteMethods 和 DirectRouteMethods。

    但是,需要注意的一点是,调用此方法会将 controllerContext.RouteData 和 controllerContext.RequestContext.RouteData 属性的 RouteData 重置为找到的操作的属性。因此,您需要包装 ControllerContext 和 RequestContext 类并重新实现 RouteData 属性,这样如果您不破坏上下文很重要,setter 将不起作用。

    参考:https://aspnetwebstack.codeplex.com/workitem/1989

    【讨论】:

      猜你喜欢
      • 2015-12-18
      • 1970-01-01
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      • 2013-10-28
      • 2014-02-07
      • 1970-01-01
      相关资源
      最近更新 更多