RequestContext - RouteData 不包含操作

RequestContext - RouteData does not contain action

所以我创建了自己的 ControllerFactory 并重载了 GetControllerSessionBehavior 以扩展 MVC 行为。

为了完成我的自定义工作,我必须对调用的操作使用反射。但是我偶然发现了一个奇怪的问题 - 我无法通过访问 RequestContext.RouteData

来检索操作

在为此设置复制示例时,我无法重现错误。

是否有人知道造成这种情况的可能原因或知道如何通过使用除此之外的请求上下文调用方法来检索操作?

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        if (!requestContext.RouteData.Values.ContainsKey("action"))
            return base.GetControllerSessionBehavior(requestContext, controllerType);

        var controllerAction = requestContext.RouteData.Values["action"];
        var action = controllerAction.ToString();

        var actionMethod = controllerType.GetMember(action, MemberTypes.Method, BindingFlags.Instance | BindingFlags.Public).FirstOrDefault();
        if(actionMethod == null)
            return base.GetControllerSessionBehavior(requestContext, controllerType);

        var cattr = actionMethod.GetCustomAttribute<SessionStateActionAttribute>();
        if (cattr != null)
            return cattr.Behavior;

        return base.GetControllerSessionBehavior(requestContext, controllerType);
    }
}

我可以很好地调用但无法访问我的控制器工厂中的操作名称的操作:

    [Route("Open/{createModel:bool?}/{tlpId:int}/{siteId:int?}")]
    public ActionResult Open(int tlpId, int? siteId, bool? createModel = true)
    {
    }

欢迎提出任何想法。

更新:

问题似乎与属性路由有关。虽然它在复制中工作正常,但对我来说在生产中不起作用。

一路上发现了这个 - 一旦 this 得到回答,我想我也会有合适的解决方案。

更新二:

有趣。复制 MVC 版本 5.0.0.0,生产 5.2.2。可能引入错误?

我可以确认 5.0.0 和 5.1.1 之间的属性路由发生了重大变化。我报告了这个问题 here。但是,对于我的用例,Microsoft 能够提供可接受的解决方法。

另一方面,您遇到的问题看起来像是另一个罪魁祸首。对于属性路由,路由值存储在名为 MS_DirectRouteMatches 嵌套 路由键中。我不确定到底是哪个版本发生了变化,但我知道它发生在 v5+.

因此,要解决您的问题,您需要检查是否存在嵌套的 RouteData 集合,并在存在的情况下使用而不是普通的 RouteData。

var routeData = requestContext.RouteData;
if (routeData.Values.ContainsKey("MS_DirectRouteMatches"))
{
    routeData = ((IEnumerable<RouteData>)routeData.Values["MS_DirectRouteMatches"]).First();
}
var controllerAction = routeData.Values["action"];
var action = controllerAction.ToString();

顺便说一句 - 在您提供的 linked question 中,提问者假设请求有可能匹配多个路由。但这是不可能的——一个请求将匹配 0 或 1 个路由,但绝不会超过一个。