1

I have classes that create a hierarchy such as this:

public interface IHandler<T, T2> {
}

public class BaseHandler : IHandler<T, T2> {
}

public class DerivedHandler : BaseHandler {
}

Basically, the idea is that the functionality can be stacked (each derived level will append more functionality).

I am trying to use the Ninject Conventions Extensions to bind this in a nice way. What I have is this:

kernel.Bind(
    x =>
        x.FromAssemblyContaining(typeof(IHandler<,>))
         .SelectAllClasses()
         .EndingWith("Handler")
         .BindAllInterfaces());

This works flawlessly when I request the DerivedHandler. Ninject doesn't complain at all. However, when I request a BaseHandler, I am presented with a:

More than one matching bindings are available.

Obviously the conventions extension is accounting for the inheritance. When I request a BaseHandler.. should it give me a BaseHandler or a DerivedHandler? (I want the BaseHandler..).

Is there a way to avoid this? I have tried all sorts of combinations of the fluent syntax and I can either get the "Multiple bindings" error.. or "No bindings found" error.

Note that this works perfectly if I manually bind each one. I assume that proves there is no issue with Ninject handling this.. its just the Conventions.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • You need to create the binding yourself and use reflection to determine the interface which is not implemented by another interface of the type... i'll post a solution. – BatteryBackupUnit Feb 04 '14 at 09:59
  • So I have to abandon using Conventions? ... I was afraid someone would say that :( Perhaps I could wrap your (forthcoming.. hopefully? :)) solution in a custom binding generator? – Simon Whitehead Feb 04 '14 at 10:01
  • No, sorry, i was expressing myself badly. You can use the convention syntax to find all types you want to bind, but you will have to implement the "Binding Generator" youself (the .BindToAllInterfaces(), or .BindToSingleInterface() part). – BatteryBackupUnit Feb 04 '14 at 10:02
  • Fantastic. I eagerly await your answer :D – Simon Whitehead Feb 04 '14 at 10:03
  • Can you eleaborate a bit on "when i request the ...". What Type do you request exactly? – BatteryBackupUnit Feb 04 '14 at 10:13
  • If I request the `BaseHandler`.. it fails with the multiple binding error. If I request `DerivedHandler`.. it happily gives me an instance. – Simon Whitehead Feb 04 '14 at 10:14
  • Whenever you are requesting a class-type you don't need to create a binding at all. kernel.Get --> ninject instantiates SomeClass as if you had done kernel.Bind().ToSelf(). – BatteryBackupUnit Feb 04 '14 at 10:16

1 Answers1

2

In your example you are requesting the concrete (class-)type you want to be instantiated.

Instead of binding .BindAllInterfaces() you need to use .BindToSelf() in the convention.

However, if you don't need to configure the binding any further (like .InSingletonScope(), or .OnActivation()...) you can also omit the binding, because whenever you are requesting a class-type which is unbound, ninject will try to instanciate the requested type.

Full Example:

kernel.Bind(x => x
     .FromAssemblyContaining(typeof(IHandler<,>))
     .SelectAllClasses()
     .EndingWith("Handler")
     .BindToSelf());
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • +1. I left out some (what I didn't think was important) information, in that the requests are made by a Factory created via the Ninject Factories extension. It does in fact resolve types via the interface.. not concrete implementations. I have decided to go with Composition-over-Inheritance in this scenario.. and all is now working as expected. Many thanks for your help anyway. – Simon Whitehead Feb 04 '14 at 10:27