问题
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