Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute Action Filter before Authorization Filter MVC 4

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??

like image 424
Mr-DC Avatar asked Jul 15 '12 23:07

Mr-DC


People also ask

How action filter is implemented in MVC?

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.

Which action filter executes last in an MVC application?

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.

How do you implement an action filter?

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.


1 Answers

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.

like image 105
Carsten Schütte Avatar answered Sep 22 '22 14:09

Carsten Schütte