How do I get the MethodInfo of an action, given action, controller and area names?

前端 未结 4 603
被撕碎了的回忆
被撕碎了的回忆 2020-12-06 07:19

What I have is the following extension method:

public MyCustomAttribute[] GetActionAttributes(
    this Controller @this,
    string action,
    string contr         


        
相关标签:
4条回答
  • 2020-12-06 08:00

    This is a short notice! Be sure to use filterContext.RouteData.DataTokens["area"]; instead of filterContext.RouteData.Values["area"];

    Good Luck.

    0 讨论(0)
  • 2020-12-06 08:02

    I have looked inside MVC 3 source code, and tested with MVC 4, and discovered how to do it. I have tagged the question wrong... it is not for MVC 3, I am using MVC 4. Though, as I could find a solution looking at MVC 3 code, then it may work with MVC 3 too.

    At the end... I hope this is worth 5 hours of exploration, with a lot trials and errors.

    Works with

    • MVC 3 (I think)
    • MVC 4 (tested)

    Drawbacks of my solution

    Unfortunately, this solution is quite complex, and dependent on things that I don't like very much:

    • static object ControllerBuilder.Current (very bad for unit testing)
    • a lot of classes from MVC (high coupling is always bad)
    • not universal (it works with MVC 3 default objects, but may not work with other implementations derived from MVC... e.g. derived MvcHandler, custom IControllerFactory, and so on ...)
    • internals dependency (depends on specific aspects of MVC 3, (MVC 4 behaves like this too) may be MVC 5 is different... e.g. I know that RouteData object is not used to find the controller type, so I simply use stub RouteData objects)
    • mocks of complex objects to pass data (I needed to mock HttpContextWrapper and HttpRequestWrapper in order to set the http method to be POST or GET... these pretty simple values comes from complex objects (oh god! =\ ))

    The code

    public static Attribute[] GetAttributes(
        this Controller @this,
        string action = null,
        string controller = null,
        string method = "GET")
    {
        var actionName = action
            ?? @this.RouteData.GetRequiredString("action");
    
        var controllerName = controller
            ?? @this.RouteData.GetRequiredString("controller");
    
        var controllerFactory = ControllerBuilder.Current
            .GetControllerFactory();
    
        var controllerContext = @this.ControllerContext;
    
        var otherController = (ControllerBase)controllerFactory
            .CreateController(
                new RequestContext(controllerContext.HttpContext, new RouteData()),
                controllerName);
    
        var controllerDescriptor = new ReflectedControllerDescriptor(
            otherController.GetType());
    
        var controllerContext2 = new ControllerContext(
            new MockHttpContextWrapper(
                controllerContext.HttpContext.ApplicationInstance.Context,
                method),
            new RouteData(),
            otherController);
    
        var actionDescriptor = controllerDescriptor
            .FindAction(controllerContext2, actionName);
    
        var attributes = actionDescriptor.GetCustomAttributes(true)
            .Cast<Attribute>()
            .ToArray();
    
        return attributes;
    }
    

    EDIT

    Forgot the mocked classes

    class MockHttpContextWrapper : HttpContextWrapper
    {
        public MockHttpContextWrapper(HttpContext httpContext, string method)
            : base(httpContext)
        {
            this.request = new MockHttpRequestWrapper(httpContext.Request, method);
        }
    
        private readonly HttpRequestBase request;
        public override HttpRequestBase Request
        {
            get { return request; }
        }
    
        class MockHttpRequestWrapper : HttpRequestWrapper
        {
            public MockHttpRequestWrapper(HttpRequest httpRequest, string httpMethod)
                : base(httpRequest)
            {
                this.httpMethod = httpMethod;
            }
    
            private readonly string httpMethod;
            public override string HttpMethod
            {
                get { return httpMethod; }
            }
        }
    }
    

    Hope all of this helps someone...

    Happy coding for everybody!

    0 讨论(0)
  • You can achieve this functionality by using the AuthorizeAttribute. You can get the Controller and Action name in OnAuthorization method. PLease find sample code below.

     public sealed class AuthorizationFilterAttribute : AuthorizeAttribute
        {
            /// <summary>
            /// Use for validate user permission and  when it also validate user session is active.
            /// </summary>
            /// <param name="filterContext">Filter Context.</param>
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                string actionName = filterContext.ActionDescriptor.ActionName;
                string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
                if (!IsUserHasPermission(controller, actionName))
                {
                   // Do your required opeation
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-06 08:12

    if you have a default route configured like

    routes.MapRoute(
            "Area",
            "",
            new { area = "MyArea", controller = "Home", action = "MyAction" }
        );
    

    you can get the route information inside the controller action like

    ht tp://localhost/Admin

    will give you

    public ActionResult MyAction(string area, string controller, string action)
    {
     //area=Admin
     //controller=Home
     //action=MyAction
     //also you can use RouteValues to get the route information
    }
    

    here is a great blog post and a utility by Phil Haack RouteDebugger 2.0

    0 讨论(0)
提交回复
热议问题