How to perform an action filter before an MVC 4 authorization filter

I implemented my own authorization attribute in MVC 4, inheriting from the AuthorizeAttribute class. I also have a custom ActionFilterAttribute . Both of them work fine, but the problem is their ordering. I need a custom action filter to run before a custom authorization filter.

I tried to use the Order property for attributes, but as I understand it, authorized filters will always run before Action Filters.

Does anyone know how to get an action filter to execute before an authorized filter?

+7
source share
1 answer

When you look at the source code (available at http://aspnetwebstack.codeplex.com/ ), you will see that this is not possible using standard filter classes, IAuthorizationFilter implementations are always executed before IActionFilter implementations. This is because action filters will not be executed when authorization filters return a result.

To solve this problem, you can create your own descendant ControllerActionInvoker class and override the InvokeAction method:

 public class MyControllerActionInvoker : ControllerActionInvoker { public override bool InvokeAction(ControllerContext controllerContext, string actionName) { // Your initialization code here try { return base.InvokeAction(controllerContext, actionName); } finally { // Your finalization code here } } } 

You need to introduce your own class MyControllerActionInvoker in your controllers in the custom class ControllerFactory :

 public class MyControllerFactory : DefaultControllerFactory { private readonly MyControllerActionInvoker actionInvoker = new MyControllerActionInvoker(); /// <summary> /// Retrieves the controller instance for the specified request context and controller type. /// </summary> protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { var controllerInstance = base.GetControllerInstance(requestContext, controllerType); if (controllerInstance != null) { var typedController = controllerInstance as Controller; if (typedController != null) { typedController.ActionInvoker = this.actionInvoker; } } return controllerInstance; } } 

And, of course, now you need to register your own MyControllerFactory using the MVC framework. You must do this when you also register your routes:

 var controllerFactory = new MyControllerFactory(); ControllerBuilder.Current.SetControllerFactory(controllerFactory); 

This implementation works fine here.

+10
source

All Articles