How can I get controller type and action info from a url or from route data?

亡梦爱人 提交于 2019-11-27 06:49:45

问题


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:


  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.




回答2:


Here is the solution I compiled from various sources. The url variable should contain the URL of the action:

        url = "YOUR URL";
        // Original path is stored and will be rewritten in the end
        var httpContext = new HttpContextWrapper(HttpContext.Current);
        string originalPath = httpContext.Request.Path;

        try
        {
            // Fake a request to the supplied URL into the routing system
            httpContext.RewritePath(url);
            RouteData urlRouteData = RouteTable.Routes.GetRouteData(httpContext);

            // If the route data was not found (e.g url leads to another site) then authorization is denied.
            // If you want to have a navigation to a different site, don't use AuthorizationMenu
            if(urlRouteData != null)
            {
                string controllerName = urlRouteData.Values["controller"].ToString();
                string actionName = urlRouteData.Values["action"].ToString();

                // Get an instance of the controller that would handle this route
                var requestContext = new RequestContext(httpContext, urlRouteData);
                var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
                var controller = (ControllerBase) controllerFactory.CreateController(requestContext, controllerName);

                // Find the action descriptor
                var controllerContext = new ControllerContext(httpContext, new RouteData(), controller);
                var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
                var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
            }
        }
        finally
        {
            // Reset our request path.
            httpContext.RewritePath(originalPath);
        }



回答3:


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!




回答4:


MvcSiteMapProvider does this. Here is the code for this particular thing.

Here is the code



来源:https://stackoverflow.com/questions/2690779/how-can-i-get-controller-type-and-action-info-from-a-url-or-from-route-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!