dev99
dev99

Reputation: 81

How to get ActionDescriptor using action and controller names

Given the action name, controller name and HTTP verb (GET, POST .. etc), is it possible to check whether the action has (ie. is decorated by) a specific action filter attribute?

Please note: The action and controller are not the current action and controller but can be any action and controller in the app.

Thanks!

Upvotes: 8

Views: 13904

Answers (4)

user2173353
user2173353

Reputation: 4640

In case someone writes unit tests and controllerFactory is not working for him as in Miguel Angelo's answer, this is the best I came up with so far:

var ctrl = // your controller instance of type T.
var controllerDescriptor = new ReflectedControllerDescriptor(ctrl.GetType());
var actionDescriptor = new ReflectedActionDescriptor(typeof(T).GetMethod(actionName), actionName, controllerDescriptor);

It doesn't locate the controller itself (it assumes the controller), but you can usually do this when writing tests...

Upvotes: 1

AntonJ
AntonJ

Reputation: 519

I had a similar problem where I needed to check if an action had a custom attribute.

public static IEnumerable<MyCustomAttribute> GetAttributes(string controllerName, string actionName)
    {
        var types = Assembly.GetExecutingAssembly().GetTypes();
        var controllers = types.Where(t => (t.Name == controllerName));
        var action = controllers.SelectMany(type => type.GetMethods().Where(a => a.Name == actionName)).FirstOrDefault();
        return action.GetCustomAttributes<MyCustomAttribute>(true);
    }

Credit to this SO answer

Upvotes: 4

Miguel Angelo
Miguel Angelo

Reputation: 24202

I have answered my own question, that is very similar to this.

You will also need the http method (that is GET, POST) to get the correct result, in addition to action and controller names.

This is the piece of the code that solves your problem:

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

Upvotes: 4

RredCat
RredCat

Reputation: 5421

I am not pretty sure that understand in which place you want to check it. If you are doing it in OnActionExecuting or OnActionExecuted. ActionExecutedContext has property ActionDescriptor. There you can find IsDefined method which gets possibility to check whether one or more instances of the specified attribute type are defined for this member. Check code sample bellow:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var hasAutorizeAttr = filterContext.ActionDescriptor
                            .IsDefined(typeof(AuthorizeAttribute), false);
    base.OnActionExecuted(filterContext);
}

EDIT: OK, now I get your issue. Looks like there no elegant solution. If you need to play in AjaxExtensions.BeginForm method with checking of others actions I see only one way - Reflection. But in my opinion you need to rethink your architecture in this case.

Upvotes: 0

Related Questions