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?
source to share
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.
source to share