RequestContext - RouteData contains no actions

So, I created my own ControllerFactory and I overload GetControllerSessionBehavior to extend the MVC behavior.

To do my own work, I have to use reflection on the action being called. However I stumbled upon a strange problem - I cannot get the action by accessing RequestContext.RouteData strong>

While creating a playback sample for this, I was unable to reproduce the error.

Does anyone know about the possible reasons for this, or knows how to get the action by calling a method with a different request context?

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

      

The action I can call just fine, but I can't access the name of the action inside my factory controller:

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

      

Any ideas are appreciated.

Update:

The problem seems to be related to attribute routing. While it works great in reproduction, it doesn't work for me.

Found this along the way - as soon as this is answered, I will find my correct solution too.

Update 2:

Interesting. Play MVC Version 5.0.0.0, Production 5.2.2. Possible error introduction?

+2


source to share


1 answer


I can confirm that there was a break in attribute routing between 5.0.0 and 5.1.1. I have reported the issue here . However, for my use case, Microsoft was able to provide an acceptable workaround.

On the other hand, the problem you are facing looks like another culprit. For attribute routing, route values ​​are stored in a nested named route key MS_DirectRouteMatches

. I don't know exactly which version changed, but I know it happened v5 +.

So, to fix your problem, you will need to check for the nested RouteData collection and use it instead of the regular RouteData in case it exists.



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

      

BTW. In the related question you posted, the searcher suggested that there is a possibility that the request could match multiple routes. But this is not possible - the request will match 0 or 1 routes, but no more than one.

+4


source







All Articles