Simple Injector property injection on action filte

2019-01-24 13:24发布

问题:

The action filter I want to inject into starts like this

public class UserAuthorisation : AuthorizeAttribute
{
    public IWcfClientProxy<IAppFrameworkServiceChannel>
        FrameworkServiceProxy { get; set; }

I have setup my container like this:

container.Register<IWcfClientProxy<IAppFrameworkServiceChannel>>(
    ()=> new WcfClientProxy<IAppFrameworkServiceChannel>());

container.RegisterInitializer<UserAuthorisation>(handler =>
{
    handler.FrameworkServiceProxy = container
       .GetInstance<IWcfClientProxy<IAppFrameworkServiceChannel>>();
});

When I run this the FrameworkServiceProxy property is null.

I have read this post: Simple Injector: Injecting a property in a base class and followed the answer. I have also read example in this page Simple Injector Documentation.

I am not injecting into a base class and maybe that is the issue?

## UPDATE ##

I am adding more information as I think it should be working from what has been said in Stevens answer.

I am using the NuGet package for MVC 3. This adds the following to the application:

public static class SimpleInjectorInitializer
{
    /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
    public static void Initialize()
    {
        var container = new Container();
        InitializeContainer(container);
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        container.RegisterMvcAttributeFilterProvider();
        container.Verify();
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }

    private static void InitializeContainer(Container container)
    {
        container.Register<IWcfClientProxy<IAppFrameworkServiceChannel>>(() => new WcfClientProxy<IAppFrameworkServiceChannel>());
        container.RegisterInitializer<UserAuthorisation>(handler =>
            {
                handler.FrameworkServiceProxy = container.GetInstance<IWcfClientProxy<IAppFrameworkServiceChannel>>();
            });
    }

This includes the container.RegisterMvcAttributeFilterProvider(); that as I now understand it should register a filter provider and should mean that filters are created through the container (this understanding might be wrong) and then properties are automatically wired-up.

My filter is registered in the Global.asax.cs like so:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new UserAuthorisation());
}

It seems to me that the filter is not being created by the container so I think I need to do something else to get that to happen ?

回答1:

You are registering an initializer on your UserAuthorisation attribute. Initializers however, are only used by the container when a type is created by the container itself. Since attributes are created by the CLR, the initializer won't go off.

The SimpleInjector.Integration.Web.Mvc.dll (this NuGet package) contains a RegisterMvcAttributeFilterProvider extension method. This will register an AttributeFilterProvider that will do implicit property injection (and call into the container.InjectProperties method). After calling container.RegisterMvcAttributeFilterProvider(), you will see that this property is injected automatically.



回答2:

I have selected Stevens answer as the answer as it got me to a solution and I am now using the command handler that he mentioned in the comments.

I have put a simple work around in to get my global filters injected.

In the App_Start\SimpleInjectorInitializer.cs I have added RegisterGlobalFilters like this:

public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
    //Add simple injector resolved types.
    filters.Add(container.GetInstance<UserAuthorisation>());
}

And in the Initialize method I have added this RegisterGlobalFilters(GlobalFilters.Filters, container);

The complete method looks like this:

/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
    var container = new Container();
    InitializeContainer(container);
    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    container.RegisterMvcAttributeFilterProvider();
    container.Verify();
    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

    RegisterGlobalFilters(GlobalFilters.Filters, container);
}

As I said very simple. Just get my instances from simple injector and then add them to the global list, I am sure there are better ways to do this.

This way does mean you do not need to change the global.asax.cs which is possibly a good thing.