Search code examples
asp.net-mvcasp.net-mvc-3action-filteractionfilterattribute

MVC3: Grouping Action Filters or calling Action Filters from other action filters


I'm trying to write an attribute class that can be used on all my "admin" actions which then effectively applies all relevant action/auth filters to that action. For instance, I always apply the AuthoriseAttribute and a custom AdminLayoutAttribute, so my intention is to just have an AdminAttribute which somehow implies both the above. That way I can make changes to the entire Admin section in one handy place.

However I don't see how I can do this. Can any one point me in the right direction?

Much appreciated.


Solution

  • You could consider moving them from the actions to a controller class or a base controller class for the Admin actions. That way you would just set both the Authorize and AdminLayout attributes in the controller class instead of each individual action method.

    [Authorize]
    [AdminLayout]
    public AdminController: Controller
    {
        //action methods
    }
    

    Having an attribute combining the authorization and some custom layout logic could be seen as a break of the Single Responsibility Principle, but if you have no other choice then you could try these approaches:

    If you want to replace your existing AdminLayoutAttribute by a new AdminAttribute, you could then create the AdminAttribute so it inherits from the standard AuthorizeAttribute and also implements IActionFilter\IResultFilter as in your custom AdminLayoutAttribute.

    public class AdminLayoutAttribute: AuthorizeAttribute, IActionFilter, IResultFilter
    {
        //Logic as in existing AdminLayoutAttribute to be replaced
    }
    

    Otherwise if you want to keep your existing AdminLayoutAttribute and add a new AdminAttribute that combines it with the AuthorizeAttribute, you could then inherit from your custom attribute and implement IAuthorizationFilter by calling an internal instance of type AuthorizationFilter

    public class AdminLayoutAttribute: AdminLayoutAttribute, IAuthorizationFilter
    {
        //Implement IAuthorizationFilter by delegating to an internal AuthorizeFilter instance
        private _authorizeFilter = new AuthorizeAttribute();
    
        public override object TypeId 
        { 
            //override from base Attribute class as in AuthorizeAttribute class
            get { return _authorizeFilter.TypeId ; }
        }
    
        public string Roles 
        {
            get { return _authorizeFilter.Roles; }
            set { _authorizeFilter.Roles = value; }
        }
    
        public string Users 
        {
            get { return _authorizeFilter.Users; }
            set { _authorizeFilter.Users = value; }
        }
    
        public void OnAuthorization(AuthorizationContext filterContext) 
        {
            _authorizeFilter.OnAuthorization(filterContext);
        }
    
    }
    

    The key in both options is to not having the new AdminAttribute class inheriting from 2 concrete classes, as multiple inheritance is not supported by C#.