views:

114

answers:

2

How can I get the controller action (method) and controller type that will be called, given the System.Web.Routing.RouteData?

My scenario is this - I want to be able to do perform certain actions (or not) in the OnActionExecuting method for an action.

However, I will often want to know not the current action, but the "root" action being called; by this I mean I may have a view called "Login", which is my login page. This view may include another partial view "LeftNav". When OnActionExecuting is called for LeftNav, I want to be able to determine that it is really being called for the "root" aciton of Login.

I realise that by calling RouteTable.Routes.GetRouteData(actionExecutingContext.HttpContext), I can get the route for the "root" request, but how to turn this into method and type info?

The only solution I have so far, is something like:

 var routeData = RouteTable.Routes.GetRouteData(actionExecutingContext.HttpContext)
 var routeController = (string)routeData.Values["controller"]; 
 var routeAction = (string)routeData.Values["action"];

The problem with this is that "routeController" is the controller name with the "Controller" suffix removed, and is not fully qualified; ie it is "Login", rather than "MyCode.Website.LoginController".

I would far rather get an actual Type and MethodInfo if possible, or at least a fully qualified type name.

Any thoughts, or alternative approaches?

[EDIT - this is ASP.Net MVC 1.0]

+1  A: 
public Type ControllerType(string controllerName)
{
   var fullName = controllerName + "Controller";
   var assemblyName = Assembly.GetExecutingAssembly().FullName;
   return Activator.CreateInstance(assemblyName, fullTypeName).GetType();
}

public MethodInfo ActionMethodInfo(string actionName, Type controllerType)
{
   return controllerType.GetMethod(actionName);
}

Are you thinking of an implementation similar to this? Some Try/Catches required!!!

Kindness,

Dan

Daniel Elliott
Thanks Dan - that is kinda where I'm headed, but really hoping to avoid. Underneath somewhere, MVC knows exactly what method, on what type, it is going to call. The problem with this approach (and mine) is that I'm having to append the suffix "Controller", and will also have to prepend the namespace to the type, etc, etc. It would probably work, but if I can hook into what MVC is doing already, I'd rather do it that way.
Rob Levine
+2  A: 
  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
     var type1 = filterContext.Controller.GetType();
     var type2 = filterContext.ActionDescriptor
                    .ControllerDescriptor.ControllerType;
  }

OK, sorry, I missed the "root" part.

Then, another way, you can save controller type to thread storage. Pseudocode:

  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
     if (!Thread.LocalStorage.Contains("root_controller"))
        Thread.LocalStorage["root_controller"] = 
            filterContext.ActionDescriptor
                    .ControllerDescriptor.ControllerType;
  }

Just an idea. I'm sure thread local storage is available in C#. The key idea here is that you save it only for first request, thus it's always root controller.

queen3
Unfortunately, this won't work as it returns the type of the *current* controller action, not the "root" controller action in the example I gave. The reason I call GetRouteData(actionExecutingContext.HttpContext) is because this does succesfully give me the route for the "root", but I can't then translate this into the controller type and method.
Rob Levine
That is a very interesting suggestion - thanks queen3
Rob Levine
Don't use ThreadLocal storage from within an ASP.NET application. ASP.NET requests can jump around between threads, so ThreadLocal storage can disappear when you don't expect it. Use HttpContext.Items instead if you need to store information that sticks around only for the current request.
Levi
Actually I just was not aware of any ASP.NET collection that stores data only for current request. Sure it's better than thread storage. Thanks for the tip.
queen3