Как получить MethodInfo действия, заданного действия, имени контроллера и области?

У меня есть следующий метод расширения:

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

Как ASP.NET MVC 3 находит метод действия, учитывая область, контроллер, имена действий и метод (GET, POST)?

На данный момент у меня ничего нет ... никаких подсказок о том, как это сделать.

В настоящее время я ищу трассировку стека внутри действия контроллера, чтобы выяснить, как MVC обнаружил его.

Зачем мне эти атрибуты

Мои атрибуты содержат информацию о том, может ли данный пользователь получить к нему доступ или нет ... но в зависимости от того, могут ли они получить к нему доступ, я хочу• чтобы показать или скрыть некоторые HTML-поля, ссылки и другие вещи, которые могут вызвать это действие.

Другое использование

Я подумал об использовании этого для размещения атрибута над действием, которое сообщает классу css ссылки, которая будет отображаться для его вызова ... и некоторые другие подсказки пользовательского интерфейса ... и затем создаю HtmlHelper, который будет отображать эту ссылку , глядя на эти атрибуты.

Не дубликат

Да, некоторые скажут, что это, возможно, дубликат этого вопроса ... у которого нет ответа, который я хочу:

Как я могу получить MethodInfo действия контроллера, которое будет вызвано при запросе?

Тот'Поэтому я уточнил обстоятельства моего вопроса.

Ответы на вопрос(4)

если у вас есть маршрут по умолчанию, настроенный как

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
}

Вот отличный пост в блоге и утилита от Фила ХаакаRouteDebugger 2.0

Вы можете достичь этой функциональности, используяAuthorizeAttribute, Вы можете получить имя контроллера и действия вOnAuthorization метод. Пожалуйста, найдите образец кода ниже.

 public sealed class AuthorizationFilterAttribute : AuthorizeAttribute
    {
        /// 
        /// Use for validate user permission and  when it also validate user session is active.
        /// 
        /// Filter Context.
        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
            }
        }
    }

Это короткое уведомление! Обязательно используйте filterContext.RouteData.DataTokens ["площадь"]; вместо filterContext.RouteData.Values ["площадь"];

Удачи.

Я заглянул внутрь исходного кода 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)макеты сложных объектов для передачи данных (Мне нужно было издеватьсяHttpContextWrapper а такжеHttpRequestWrapper для того, чтобы установитьhttp method бытьPOST или жеGET... эти довольно простые значения происходят от сложных объектов (о боже! = \))Код
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()
        .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; }
        }
    }
}

Надеюсь, что все это помогает кому-то ...

Удачного кодирования для всех!

Ваш ответ на вопрос