I have implemented my own custom Authorization Attribute in MVC 4 by inheriting from AuthorizeAttribute
class. I also have a custom ActionFilterAttribute
. These both work fine however the problem lies in ordering them. I need the custom Action Filter to run before the custom Authorize Filter.
I have tried using the Order
property for the attributes but as i understand it, Authorize Filters will always run before Action Filters.
Does anyone know how to force the Action Filter to execute before the Authorize Filter??
Web. Mvc. FilterAttribute class. If you want to implement a particular type of filter, then you need to create a class that inherits from the base Filter class and implements one or more of the IAuthorizationFilter , IActionFilter , IResultFilter , or IExceptionFilter interfaces.
Exception Filters − Exception filters are the last type of filter to run. You can use an exception filter to handle errors raised by either your controller actions or controller action results.
You can create a custom action filter in two ways, first, by implementing the IActionFilter interface and the FilterAttribute class. Second, by deriving the ActionFilterAttribute abstract class.
When you take a look at the source code (available at http://aspnetwebstack.codeplex.com/) you see that this is not possible with the standard Filter classes. IAuthorizationFilter
implementations are always executed before IActionFilter
implementations. That's because action filters will not run when authorization filters return a result.
To solve this you can create your own ControllerActionInvoker
descendant 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 inject your custom MyControllerActionInvoker
class into your controllers in a custom ControllerFactory
class:
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 you now have to register your own MyControllerFactory
with the MVC framework. You should do this where you're also registering your routes:
var controllerFactory = new MyControllerFactory();
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
This implementation works fine here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With