How to retrieve attributes of requested Action Method
asp.net-mvc-3, c#, html-helper, reflection
Solution
EDIT: Updated the method to include insights from this page. This final version peeks the `AuthorizationFilters` for the requested action method and checks whether the user is authorized to perform the action.
So I dug around in `System.Web.Mvc.ControllerActionInvoker` and found the methods and constructors I needed. `ControllerDescriptor.FindAction()` ended up being the key. Below, I've copied the method I wrote that will retrieve all the attributes:
private static bool _IsUserAuthorized(HtmlHelper htmlHelper,
string controllerName,
string actionName)
{
ControllerContext controllerContext = null;
// if controllerName is null or empty,
// we'll use the current controller in HtmlHelper.ViewContext.
if (string.IsNullOrEmpty(controllerName))
{
controllerContext = htmlHelper.ViewContext.Controller.ControllerContext;
} else { // use the controller factory to get the requested controller
var factory = ControllerBuilder.Current.GetControllerFactory();
var controller = (ControllerBase)factory.CreateController(
htmlHelper.ViewContext.RequestContext, controllerName);
controllerContext = new ControllerContext(
htmlHelper.ViewContext.RequestContext, controller);
}
var controllerType = controllerContext.Controller.GetType();
var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
var actionDescriptor = controllerDescriptor.FindAction(
controllerContext, actionName);
if (actionDescriptor == null)
{
return false;
}
var filters = new FilterInfo(
FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)
);
var authContext = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter authFilter in filters.AuthorizationFilters)
{
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
{
return false;
}
}
return true;
}
Problem
I'm trying to peek at any authentication attributes which may be decorating action methods in my controllers in an MVC 3 application. I'm doing this in my own HtmlHelper extension methods which are basically wrappers to ActionLink (to give you the context of what information I have available at runtime). I have a basic solution in place, but overloaded methods have just made it explode. I know that the framework is internally resolving urls to action methods, but after looking through the code for System.Web.Mvc.LinkExtensions, I still haven't found precisely how that is happening, so I'm a bit stuck as to how to tackle this issue. Here's the code I have so far for resolving the relevant method: ``` private static bool _IsUserAuthorized(HtmlHelper html, string controllerName, string actionName) { controllerName = controllerName ?? html.ViewContext.RouteData.GetRequiredString("controller"); var factory = ControllerBuilder.Current.GetControllerFactory(); var controller = factory.CreateController( html.ViewContext.RequestContext, controllerName); Type controllerType = controller.GetType(); var methodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); ... check authentication } ``` So my current problem is that when a method is overridden, I get "ambiguous match found" exceptions. I'm guessing I need to process the RouteValues to resolve any parameters to the method so I can unambiguously identify the right one. Does anyone have some pointers on how to do this? Alternately, does the framework already provide a means of resolving the exact method needed? Thanks so much!