给定动作,控制器和区域名称,如何获取动作的MethodInfo?

时间:2012-10-24 03:58:38

标签: asp.net-mvc-3

我所拥有的是以下扩展方法:

public MyCustomAttribute[] GetActionAttributes(
    this Controller @this,
    string action,
    string controller,
    string area,
    string method)
{
}

ASP.NET MVC 3如何根据区域,控制器,操作名称和方法(GET,POST)找到操作方法?

到目前为止,我什么都没有......没有关于如何做到这一点的线索。

我目前正在寻找控制器动作中的堆栈跟踪,以了解MVC如何发现它。

为什么我需要这些属性

我的属性包含有关给定用户是否可以访问它的信息...但是根据他们是否可以访问它,我不想显示或隐藏某些html字段,链接和其他可能的内容称之为行动。

其他用途

我曾想过使用它来在一个动作上放置一个属性,告诉css类将被渲染的链接调用它......以及其他一些UI提示......然后构建一个HtmlHelper,它将会渲染该链接,查看这些属性。

不重复

是的,有人会说这可能是这个问题的重复...... 没有我想要的答案:

How can i get the MethodInfo of the controller action that will get called given a request?

这就是我说明问题情况的原因。

4 个答案:

答案 0 :(得分:9)

我查看了MVC 3源代码,并使用MVC 4进行了测试,并发现了如何做到这一点。 我已经标记了错误的问题......它不适用于MVC 3,我使用的是MVC 4.虽然我可以找到一个查看MVC 3代码的解决方案,但它也可以与MVC 3一起使用。

最后......我希望这需要5个小时的探索,经过大量的试验和错误。

使用

  • MVC 3(我认为)
  • MVC 4(已测试)

我的解决方案的缺点

不幸的是,这个解决方案非常复杂,并且依赖于我不太喜欢的事情:

  • 静态对象ControllerBuilder.Current (单元测试非常糟糕)
  • 很多来自MVC的课程(高耦合总是很糟糕)
  • 不通用(它适用于MVC 3默认对象,但可能不适用于从MVC派生的其他实现...例如派生的MvcHandler,自定义IControllerFactory等等)
  • 内部依赖(取决于MVC 3的具体方面,(MVC 4的行为也是如此)可能是MVC 5不同......例如我知道RouteData对象不是用于查找控制器类型,因此我只使用存根RouteData对象)
  • 模拟复杂对象传递数据(我需要模拟HttpContextWrapperHttpRequestWrapper才能将http method设置为POSTGET ......这些非常简单的值来自复杂的物体(天啊!= \))

代码

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

修改

忘记模拟的课程

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

希望所有这些都有助于某人...

为所有人编写快乐代码!

答案 1 :(得分:3)

您可以使用 AuthorizeAttribute 来实现此功能。您可以在 OnAuthorization 方法中获取Controller和Action名称。请在下面找到示例代码。

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

答案 2 :(得分:0)

如果您的默认路由配置为

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

您可以在控制器操作中获取路径信息,如

  

ht tp:// localhost / Admin

会给你

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
}

这是一篇很棒的博客文章和Phil Haack RouteDebugger 2.0

的实用程序

答案 3 :(得分:0)

这是一个简短的通知!一定要使用filterContext.RouteData.DataTokens [“area”];而不是filterContext.RouteData.Values [“area”];

祝你好运。