How to rewrite code to use IAuthorizationFilter with dependency injection instead of AuthorizeAttribute with service location in Asp Net Web Api?

Viewed 3714

I have the custom AuthorizeAttribute where I need to use one of the business layer services to validate some data in the database before giving user a permission to view the resource. In order to be able to allocate this service within the my AuthorizeAttribute I decided to use service location "anti-pattern", this is the code:

internal class AuthorizeGetGroupByIdAttribute : AuthorizeAttribute
{
    private readonly IUserGroupService _userGroupService;

    public AuthorizeGetGroupByIdAttribute()
    {
        _userGroupService = ServiceLocator.Instance.Resolve<IUserGroupService>();
    }

    //In this method I'm validating whether the user is a member of a group. 
    //If they are not they won't get a permission to view the resource, which is decorated with this attribute.
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        Dictionary<string, string> parameters = actionContext.Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value);
        int groupId = int.Parse(parameters["groupId"]);
        int currentUserId = HttpContext.Current.User.Identity.GetUserId();

        return _userGroupService.IsUserInGroup(currentUserId, groupId);
    }

    protected override void HandleUnauthorizedRequest(HttpActionContext actionContex)
    {
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
        {
            base.HandleUnauthorizedRequest(actionContex);
        }
        else
        {
            actionContex.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
        }
    }
}

I have couple of other attributes like this in my application. Using service locator is probably not a good approach. After searching the web a little bit I found some people suggesting to use IAuthorizationFilter with dependency injection instead. But I don't know how to write this kind of IAuthorizationFilter. Can you help me writing IAuthorizationFilter that will do the same thing that the AuthorizeAttribute above?

2 Answers

Perhaps try it like shown here:

Add the following public method to your class.

public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
    // gets the dependecies from the serviceProvider 
    // and creates an instance of the filter
    return new GetGroupByIdAuthorizationFilter(
        (IUserGroupService )serviceProvider.GetService(typeof(IUserGroupService )));
}

Also Add interface IFilterMetadata to your class.

Now when your class is to be created the DI notices that there is a CreateInstance method and will use that rather then the constructor.

Alternatively you can get the interface directly from the DI in your method by calling

context.HttpContext.Features.Get<IUserGroupService>()
Related