Dependency injection with IAuthorizationFilter in SimpleInjector

江枫思渺然 提交于 2020-06-28 06:04:16

问题


I have a class PermissionFilter that implements IAuthorizationFilter from System.Web.Mvc. Since it has dependencies that are already mapped, I want to use SimpleInjector to provide it.

I'm doing this (which was working with Ninject):

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(DependencyResolver.Current.GetService(typeof(PermissionFilter)));
}

But I get the error:

Value cannot be null. Parameter name: instance

I tried to get an instance of the PermissionFilter from the container:

var permissionFilter = container.GetInstance(typeof(PermissionFilter));
filters.Add(permissionFilter);

But with SimpleInjector, when it reaches this code:

container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

I get an InvalidOperationException with the message:

The container can't be changed after the first call to GetInstance, GetAllInstances and Verify. Please see https://simpleinjector.org/locked to understand why the container is locked.


回答1:


As I was writing the question, I was prompted by SO to check this question and the great answer by Steven. There he says:

MVC global filters are just a list of instances. This means that any dependencies such filter has, also become singletons. This means you should be very careful with this approach, because it is really easy to accidentally cause a Captive Dependency in your application. Captive Dependencies are often hard to track and often only popup in testing or production.

Instead, you should create a proxy class that can delegate back to your container/kernel at the time the filter is used, so it can resolve the real filter on the spot. This prevents Captive Dependencies.

So, I ended up writing this proxy class:

public class AuthorizationFilterProxy<TFilter> : IAuthorizationFilter
    where TFilter : class, IAuthorizationFilter
{
    private readonly Container Container;

    public AuthorizationFilterProxy(Container container)
    {
        Container = container;
    }

    public void OnAuthorization(AuthorizationContext context)
    {
        Container.GetInstance<TFilter>().OnAuthorization(context);
    }
}

To add the filter:

public static void RegisterGlobalFilters(
    GlobalFilterCollection filters, Container container)
{
    // Since PermissionFilter is a root type (i.e. directly resolved from the container),
    // it should be explicitly registered. This allows it to be verified.
    container.Register<PermissionFilter>();

    filters.Add(new AuthorizationFilterProxy<PermissionFilter>(container));
}


来源:https://stackoverflow.com/questions/49052523/dependency-injection-with-iauthorizationfilter-in-simpleinjector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!