Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to inject into IAsyncActionFilter from Simple Injector in ASP.NET Core project?

Consider a simple action filter in an ASP.NET Core MVC project that takes a dependency:

public class TestActionFilter : IAsyncActionFilter {
    private readonly IMyDependency _dep;

    public class TestActionFilter(IMyDependency dep)
    {
        _dep = dep;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context,
                                             ActionExecutionDelegate next)
    {
        // do things with _dep...
        await next();
    }
}

I already have IMyDependency registered with Simple Injector and working elsewhere. I would like for Simple Injector to handle the action filter as well.

If I add an IServiceCollection registration for the same type, it does get injected into the action filter. I do not want two bindings though and I'm trying to avoid the framework container and just stick with Simple Injector.

Is there some trick to get Simple Injector to handle my action filter? I remember there used to be some sort of "filter provider" concepts in older Simple Injector incarnations that allowed this.

like image 659
kenchilada Avatar asked Dec 23 '22 18:12

kenchilada


1 Answers

At this moment, there is nothing in the Simple Injector integration package for ASP.NET Core MVC that simplifies working with filter attributes. We are still hoping that Microsoft will add simplifications to the framework to support non-conformers (since Microsoft promised to make integration as smooth as it can be), but this seems a lost cause.

There are a few solutions. An approach is to cross-wiring, as you did already. But the more you cross-wire, the more you move control out of Simple Injector and the more you lose the verification ability that Simple Injector gives. This typically won't be much a problem when all your object graphs are singletons, but that's a different discussion.

Another option is to create a proxy filter in the built-in configuration system that delegates to the real filter that is resolved from Simple Injector. Such proxy can be defined as follows:

public sealed class SimpleInjectiorAsyncActionFilterProxy<TAsyncActionFilter>
    : IAsyncActionFilter
    where TAsyncActionFilter : class, IAsyncActionFilter {
    private readonly Container container;
    public SimpleInjectiorAsyncActionFilterProxy(Container container) {
        this.container = container; 
    }

    public Task OnActionExecutionAsync(
        ActionExecutingContext c, ActionExecutionDelegate n) =>
        container.GetInstance<TAsyncActionFilter>().OnActionExecutionAsync(c, n);
}

This is how you hook up your filter using this proxy:

container.Register<TestActionFilter>();

services.AddMvc(options =>
{
    options.Filters.Add(
        new SimpleInjectiorAsyncActionFilterProxy<TestActionFilter>(container));
});

This works great for global filters. When it comes to controller or action scoped filters, take a look at passive attributes.

like image 150
Steven Avatar answered May 08 '23 20:05

Steven