Find atrributes in action from ViewEngine in ASP.NET MVC
I have a custom ViewEngine and I want to change the main page used depending on whether the requested action has an attribute filter Authorize
.
So far, I just use a reflection like this:
var method = controllerContext.Controller.GetType().GetMethod(viewName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (method != null)
{
if (method.GetCustomAttributes(typeof(AuthorizeAttribute), true).Length > 0)
{
masterName = "Admin.master";
}
}
But I'm not a big fan of using reflection for repetitive tasks. I know that I can use the cache view to speed things up after the first time, but I'm wondering if there is a more direct way to access the list of filters applied to an action within a method FindView
for ViewEngine
?
a source to share
It's pretty much limited to using reflection to get any attribute information independent of anything, including MVC action methods.;)
The only other way to get this information is to go through the ControllerDescriptor paths
In your case, you can just skip looking for the authorization attribute altogether and just ask if the user is allowed or not and give them the main page they need.
I have set the master page dynamically in a custom view before and the most efficient option is to see what HttpContextBase information is available. For one scenario, I simply passed request parameters or added {masterPage} route parameters when I needed to use them.
The only other information about the action path is the ReflectedControllerDescriptor route. The problem with this method is very verbose and requires many lines of code to do what you are doing.
Here is some code (I found on stackoverflow!) Of this "descriptor" method for trimming and trimming security links. This code can also be used to dynamically set the master page if it was in a custom view engine. This is not what you are looking for, but might help someone else do the same dynamic master page setup somewhere else:
public static bool HasActionPermission( this HtmlHelper htmlHelper, string actionName, string controllerName )
{
//if the controller name is empty the ASP.NET convention is:
//"we are linking to a different controller
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName)
? htmlHelper.ViewContext.Controller
: GetControllerByName(htmlHelper, controllerName);
var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo);
var controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType());
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
return ActionIsAuthorized(controllerContext, actionDescriptor);
}
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters)
{
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
a source to share