3

Recently I decided to remove a heap of action level filters in a controller and replace them with a single controller level filter.

Now I'm getting this error message.

Error activating LogActionFilter
More than one matching bindings are available.
Activation path:
 1) Request for LogActionFilter

Suggestions:
 1) Ensure that you have defined a binding for LogActionFilter only once.

I'm sure the error is related to action filter being bound twice, as that's what I've changed. However, when I view the documentation here I can see it specifies/does the same. So I'm really not sure what I'm doing wrong.

My sample controller

[LogAction]
public class SomeController : Controller
{
    public ActionResult SomeAction()
    { 

    }
}

My registration code

public static void RegisterFilters()
{
    Kernel.BindFilter<LogActionFilter>(FilterScope.Controller, 0)
    .WhenControllerHas<LogActionAttribute>();

    Kernel.BindFilter<LogActionFilter>(FilterScope.Action, 0)
        .WhenActionMethodHas<LogActionAttribute>();
}
Plebsori
  • 1,075
  • 9
  • 23
  • 2
    FYI, `BindFilter` is an extension method from the `Ninject.Web.Mvc.FilterBindingSyntax` namespace [per this guy's post](http://stackoverflow.com/questions/6193414/dependency-injection-with-ninject-and-filter-attribute-for-asp-net-mvc/6193490#6193490) – John B Nov 04 '11 at 17:56

3 Answers3

4

This happens if your controller and one of its actions have the LogActionAttribute at the same time.

Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • Hi Remo. Thanks for taking the time to answer. I've checked for this situation and found that I don't have the filter to any other actions. I made a quick example site to confirm I can reproduce this. I'll put in on github soon and I'll post a link. – Plebsori May 04 '11 at 22:52
  • Hi Remo. If you get a chance [here is the link](https://github.com/pleb/Examples/tree/master/Ninject%20Action%20Controller%20Filter%20Problem/NinjectExample/NinjectExample.Web) to the sample project I threw up on Github – Plebsori May 04 '11 at 23:04
  • 3
    Ah sorry I was already on the next version. Support for multiple filters has been added to the current development build. You have to update to 2.3 found on the continuous integration server: teamcity.codebetter.com But be aware this is still work in progress. In terms of MVC its pretty much final though but not very well tested. – Remo Gloor May 04 '11 at 23:44
  • Prefect, I'll update to the latest version. I'll help test it ;) – Plebsori May 04 '11 at 23:50
  • 2
    @Remo, I ran into the same issue with 2.2, so I uninstalled all Ninject Nuget packages from my app. Next, I downloaded 2.3 from TeamCity and referenced all the dlls. When I tried to build, I got an error saying "The type of namespace name 'Bootsrapper' could not be found." `Bootstrapper` is used in `App_Start.NinjectMVC3`, which gets created when you install the Nuget package, but it does not appear to be part of the TeamCity build. How can I work around this problem? Better yet, would you consider releasing a Nuget package for 2.3 called "Ninject.MVC3 2.3 Preview"? – devuxer Dec 24 '11 at 07:17
  • @DanM You need Ninject.Web.Common – Remo Gloor Dec 24 '11 at 11:54
  • @Remo. Plus one for the 2.3 on NuGet. Any chance of a NuGet product line of Ninject*-NightlyBuild? – Plebsori Mar 02 '12 at 01:13
3

(I know the answer's already accepted but this is for the sake of documentation.)

In case you can only use the release version, a temporary solution is to create two subclasses and register them separately. Here's an example from my application:

public class MyAuthorizationFilter : IAuthorizationFilter
{
   /* call base ctor */
}

public class MyControllerAuthorizationFilter : MyAuthorizationFilter
{
   /* call base ctor */
}

public class MyActionAuthorizationFilter : MyAuthorizationFilter
{
}

Then setup filter bindings:

this.BindFilter<MyControllerAuthorizationFilter>(FilterScope.Controller, 0)
            .WhenControllerHas<MyAttribute>()
            .WithConstructorArgumentFromControllerAttribute<ProtectedAttribute>(/*...*/) ;

this.BindFilter<MyActionAuthorizationFilter>(FilterScope.Action, 0)
            .WhenActionMethodHas<MyAttribute>()
            .WithConstructorArgumentFromActionAttribute<ProtectedAttribute>(/*...*/) ;

Make sure to call the correct 'WithConstructorArgumentFrom[Controller/Action]Attribute method or you'll get a 'Sequence has no elements' error (I did).

1

Better workaround. In fact I use this in the new version too rather than have two bindings for controllers and actions.

this.BindFilter<MyFilter>(FilterScope.Global, int.MinValue)
    .When((controllerContext, actionDescriptor) =>
                                                 controllerContext
                                                .Controller
                                                .GetType()
                                                .GetCustomAttributes(typeof(MyAttribute),true)
                                                .Length > 0 
    || actionDescriptor.GetCustomAttributes(typeof(MyAttribute), true).Length > 0);
DalSoft
  • 10,673
  • 3
  • 42
  • 55
  • Nice one DalSoft. FYI, an easier way of testing for attributes is: Action `actionDecriptor.GetCustomAttributes(typeof(MyAttribute), true).Any()` or for controller `actionDecriptor.ControllerDescriptor.GetCustomAttributes(typeof(MyAttribute), true).Any()` – Plebsori Jul 24 '12 at 02:46