Asp.net mvc 3 如何获取动作、给定动作、控制器和区域名称的MethodInfo?

Asp.net mvc 3 如何获取动作、给定动作、控制器和区域名称的MethodInfo?,asp.net-mvc-3,Asp.net Mvc 3,我有以下扩展方法: public MyCustomAttribute[] GetActionAttributes( this Controller @this, string action, string controller, string area, string method) { } 在给定区域、控制器、操作名称和方法(GET、POST)的情况下,ASP.NET MVC 3如何找到操作方法 到现在为止我什么都没有。。。没有关于如何做到这一点的线索

我有以下扩展方法:

public MyCustomAttribute[] GetActionAttributes(
    this Controller @this,
    string action,
    string controller,
    string area,
    string method)
{
}
在给定区域、控制器、操作名称和方法(GET、POST)的情况下,ASP.NET MVC 3如何找到操作方法

到现在为止我什么都没有。。。没有关于如何做到这一点的线索

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

我为什么需要这些属性

我的属性包含有关给定用户是否可以访问它的信息。。。但取决于他们是否可以访问它,我不想显示或隐藏一些html字段、链接和其他可以调用该操作的内容

其他用途

我曾经考虑过使用它在一个动作上放置一个属性,它告诉css类将要呈现的链接调用它。。。还有其他一些UI提示。。。然后构建一个HtmlHelper来呈现链接,查看这些属性

不是重复的

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


这就是为什么我指定了问题的具体情况。

如果您有如下配置的默认路由

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的一篇很棒的博客文章和一个实用工具您可以通过使用authorized属性来实现此功能。您可以在授权方法中获取控制器和操作名称。请在下面找到示例代码

 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
            }
        }
    }
公共密封类AuthorizationFilterAttribute:AuthorizationAttribute
{
/// 
///用于验证用户权限以及验证用户会话处于活动状态时。
/// 
///过滤上下文。
授权时的公共覆盖无效(AuthorizationContext filterContext)
{
字符串actionName=filterContext.ActionDescriptor.actionName;
字符串控制器=filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
如果(!IsUserHasPermission(控制器,actionName))
{
//做你需要的操作
}
}
}

我查阅了MVC 3的源代码,并用MVC 4进行了测试,发现了如何做到这一点。 我把问题标错了。。。它不适用于MVC 3,我使用的是MVC 4。尽管如此,因为我可以找到一个查看MVC3代码的解决方案,所以它也可以与MVC3一起工作

最后。。。我希望这是值得5个小时的探索,有很多尝试和错误

  • MVC3(我想)
  • MVC 4(已测试)
我的解决方案的缺点 不幸的是,这个解决方案相当复杂,并且依赖于我不太喜欢的东西:

  • 静态对象
    ControllerBuilder.Current
    (对单元测试非常不利)
  • 来自MVC的很多类(高耦合总是不好的)
  • 不通用(它适用于MVC 3默认对象,但可能不适用于从MVC派生的其他实现…例如派生的MvcHandler、自定义IControllerFactory等…)
  • 内部依赖关系(取决于MVC 3的特定方面,(MVC 4的行为也类似于此)可能MVC 5不同…例如,我知道
    RouteData
    对象不用于查找控制器类型,所以我只使用存根RouteData对象)
  • 模拟复杂对象以传递数据(我需要模拟
    HttpContextWrapper
    HttpRequestWrapper
    ,以便将
    http方法
    设置为
    POST
    GET
    。这些非常简单的值来自复杂对象(哦,上帝!=\)
代码 希望所有这些都能帮助某人


祝大家编码愉快

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


祝你好运。

需要更多信息。可能有多个操作具有相同的名称,但响应不同的参数。您是在谈论路由参数吗?我是在谈论方法参数。多个操作方法可能具有相同的名称,但具有不同的参数。如果模型绑定器可以匹配参数,将调用正确的方法。不同的方法仍将具有相同的控制器名称和操作名称;如果使用多个方法,代码将不完整。
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; }
        }
    }
}