Search code examples
c#entity-frameworkunity-containerasp.net-web-api2unit-of-work

Implementing IAuthenticationFilter, Unit of Work and Dependency Injection


I have a Web API 2 project that is implementing a custom IAuthenticationFilter such as the following.

My problem is the UnitOfWork is not injected by Unity in the BasicAuthenticator class. As expected Unity successfully injects UnitOfWork in Controllers.

public class BasicAuthenticator : Attribute, IAuthenticationFilter
{
    [Dependency]
    public UnitOfWork UoW { get; set; }

    public bool AllowMultiple { get { return false; } }     

    public Task AuthenticateAsync(HttpAuthenticationContext context,
                                  CancellationToken cancellationToken)
    {
        // ignore missing implementation
        context.Principal = new ClaimsPrincipal(new[] { id });     
        return Task.FromResult(0);
    }

    public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
                            CancellationToken cancellationToken) {}
}

Solution

  • You will need to create a custom IFilterProvider that will perform a BuildUp() on the applicable filters. The BuildUp operation will inject all dependencies into the filter.

    Here is a UnityFilterProvider that does that:

    public class UnityFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
    {
        private readonly IUnityContainer container;
    
        public UnityFilterProvider(IUnityContainer container)
        {
            this.container = container;
        }
    
        public new IEnumerable<FilterInfo> GetFilters(
            HttpConfiguration configuration,
            HttpActionDescriptor actionDescriptor)
        {
            var filters = base.GetFilters(configuration, actionDescriptor);
    
            foreach (var filter in filters)
            {
                container.BuildUp(filter.Instance.GetType(), filter.Instance);
            }
    
            return filters;
        }
    }
    

    Next at application startup you need to replace the default filter provider with the custom provider above:

    GlobalConfiguration.Configuration.Services.Add(
        typeof(System.Web.Http.Filters.IFilterProvider),
        new UnityFilterProvider(container));
    
    var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders()
                   .ToList();
    var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);
    
    GlobalConfiguration.Configuration.Services.Remove(
        typeof(System.Web.Http.Filters.IFilterProvider), 
        defaultprovider);
    

    I usually use the Unity bootstrapper for ASP.NET Web API so I put the above code in the UnityConfig.cs after RegisterTypes().