Search code examples
c#dependency-injectionasp.net-core-mvcsimple-injector

Dependency injection failed with IAuthorizationFilter and Simple Injector for ASP.NET Core


This is very similar to this case, but solution not works for .net core 3.1.

So, I have IAuthorizationFilter:

public class AuthFilter : IAuthorizationFilter
{
    private readonly IUserService userService;
    public AuthFilter(IUserService userService)
    {
        this.userService = userService;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        Console.WriteLine("Doing authZZZ: " + userService.DoSomething());
    }
}

and simple service

public interface IUserService
{
    string DoSomething();
}

class UserService : IUserService
{
    public string DoSomething()
    {
        return "Something";
    }
}

Registering filter and service as:

services.Configure<MvcOptions>(options => options.Filters.Add<AuthFilter>());
...
container.Register<IUserService, UserService>(Lifestyle.Transient);

Everything else, as in example

And got exception while calling action:

InvalidOperationException: Unable to resolve service for type 'TestSimpleInj.IUserService' while attempting to activate 'TestSimpleInj.AuthFilter'.

Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
lambda_method(Closure , IServiceProvider , object[] )
Microsoft.AspNetCore.Mvc.TypeFilterAttribute.CreateInstance(IServiceProvider serviceProvider)
Microsoft.AspNetCore.Mvc.Filters.DefaultFilterProvider.ProvideFilter(FilterProviderContext context, FilterItem filterItem)
Microsoft.AspNetCore.Mvc.Filters.DefaultFilterProvider.OnProvidersExecuting(FilterProviderContext context)
Microsoft.AspNetCore.Mvc.Filters.FilterFactory.CreateUncachedFiltersCore(IFilterProvider[] filterProviders, ActionContext actionContext, List<FilterItem> filterItems)
Microsoft.AspNetCore.Mvc.Filters.FilterFactory.GetAllFilters(IFilterProvider[] filterProviders, ActionContext actionContext)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory+<>c__DisplayClass7_0.<CreateRequestDelegate>b__0(HttpContext context)
Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Solution

  • The answer to your question is actually almost given in the q&a you referred to, but you just need a few minor tweaks to get it working under ASP.NET Core MVC.

    You need to change the AuthorizationFilterProxy<TFilter> to the following:

    public class AuthorizationFilterProxy<TFilter> : IAuthorizationFilter
        where TFilter : class, IAuthorizationFilter
    {
        private readonly Container Container;
    
        public AuthorizationFilterProxy(Container container) =>
            this.Container = container;
    
        public void OnAuthorization(AuthorizationFilterContext context) =>
            this.Container.GetInstance<TFilter>().OnAuthorization(context);
    }
    

    Now you need to hook this AuthorizationFilterProxy<TFilter> into ASP.NET Core MVC's pipeline, which can be done as follows:

    services.Configure<MvcOptions>(options => options.Filters.Add(
        new AuthorizationFilterProxy<AuthFilter>(container)));
    
    container.Register<AuthFilter>();
    

    This, as well, is very similar to adding a global filter to ASP.NET MVC, as shown in the referenced question.

    This adds the AuthorizationFilterProxy<AuthFilter> to the list of MVC Filters and the proxy will forward the call to Simple Injector. AuthFilter is now resolved from Simple Injector, and with it its IUserService dependency.