1

My problem statement is same as this question i.e., use an injected service in attribute/filter. I have tried the solution given by B Z and following is my code along the lines of solution given.

//marker attribute
public class AuthorizeViewAttribute : Attribute { }

//filter
public class AuthorizeViewFilter : IAuthorizationFilter
{
    private readonly IAccessRightsService _iAccessRightService;
    public AuthorizeViewFilter(IAccessRightsService iAccessRightService)
    {
        _iAccessRightService = iAccessRightService;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        RoleFeature roleFeature = _iAccessRightService.GetRoleFeatures();

        if (roleFeature.IsView)
        {
            //redirect to controller
        }
    }      
}

Following is the ninject binding I use:

this.BindFilter<AuthorizeViewFilter>(System.Web.Mvc.FilterScope.Controller, 0)
        .WhenControllerHas<AuthorizeViewAttribute>();

I do not need any parameter in attribute, so I figured I do not need to use WithConstructorArgument as mentioned in this answer

But my filter never gets called. I put a default constructor in AuthorizeViewAttribute , debugged and found that the control jumps to default constructor in AuthorizeViewAttribute and continues with the controller method.

I cannot find any solution to this. Any suggestions?

supernova
  • 35
  • 7

1 Answers1

2

Short story : You seem to be trying to use MVC filter and MVC binding on a webapi controller. That's why it does not work.

Long story : first create a webapi filter provider ( note, you will need Ninject.Extensions.Factories package to have Func<AuthorizeViewFilter> resolved by Ninject)

public class AuthorizeViewFilterProvider : System.Web.Http.Filters.IFilterProvider
{
    private readonly Func<AuthorizeViewFilter> _authorizeViewFilterFactory;

    public AuthorizeViewFilterProvider(Func<AuthorizeViewFilter> authorizeViewFilterFactory)
    {
        this._authorizeViewFilterFactory = authorizeViewFilterFactory;
    }

    public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
    {
        if(!actionDescriptor.GetCustomAttributes<AuthorizeViewAttribute>().Any())
            return Enumerable.Empty<FilterInfo>();

        return new[]
        {
            new FilterInfo(this._authorizeViewFilterFactory(), FilterScope.Action)
        };
    }
}

then create a webapi filter

public class AuthorizeViewFilter : System.Web.Http.Filters.IAuthorizationFilter
{
    private readonly IAccessRightsService _iAccessRightService;
    public AuthorizeViewFilter(IAccessRightsService iAccessRightService)
    {
        _iAccessRightService = iAccessRightService;
    }

    public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(
        HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> continuation)
    {
        RoleFeature roleFeature = _iAccessRightService.GetRoleFeatures();

        if (roleFeature.IsView)
        {
            return continuation();
        }
        else
          return Task.FromResult(actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Access denied"));
    }
}

then, bind the FilterProvider in your binding setup :

this.Bind<System.Web.Http.Filters.IFilterProvider>().To<AuthorizeViewFilterProvider>();
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
jbl
  • 15,179
  • 3
  • 34
  • 101
  • Thank you! That worked! One follow up question: How would we pass attribute parameter to the filter? – supernova Feb 08 '18 at 09:55
  • 1
    As a follow up, I figured it out. We can use actionContext.actionDescriptor to get CustomAttribute and associated parameters.I also discovered this post which is pretty neat: http://blog.ploeh.dk/2014/06/13/passive-attributes/ – supernova Feb 09 '18 at 06:49