Search code examples
dependency-injectionninjectconventionsninject-extensions

How to bind services with Ninject Conventions


I have two scenarios here that I want to solve with Ninject.Extensions.Conventions.

The first is a simple one: Whenever an instance from a namespace containing the word "service" is requested, return a singleton instance of the only matching class. I tried like so:

Kernel.Bind(service => service.FromThisAssembly()
                              .Select(theClass => theClass.Namespace.Contains("Service"))
                              .BindDefaultInterface()
                              .Configure(binding => binding.InSingletonScope()));

Some of those services get resolved, but I run into an ActivationException when the resolution chain reaches a point where Impl1 has a dependency of IService2.

What could be wrong with this binding?


The second one is probably equally simple. All classes that inherit BaseClass should be instantiated via a method. This is the resolution code I used up to now, to do that per class:

Bind<MyViewModel>().ToMethod(ctx => fac.CreateProxy<MyViewModel>())
                   .InSingletonScope();

[ Note: In this case, fac is a custom factory that builds Castle proxies.]

How can I do such a thing for a classes inheriting from, say, ViewModelBase with Extensions.Conventions?

I figured out the select part already, here it is.

Kernel.Bind(ViewModel => ViewModel.FromThisAssembly()
                                  .Select(t => t.BaseType == typeof(ViewModelBase))
                                  );

Now I need to get that factory into action...


General Questions:

  1. The binding approach of Extensions.Conventions seems to be the exact reverse of the regular way:

    • Ninject : Bind <Interface>() . To <Implementation> ()

    • Conventions : SelectAllClasses().BindDefaultInterface()

      Why is that so, or a I misunderstanding this?

  2. I used to put my bindings in a class derived from NinjectModule, and I'd preferrably continue to do so. Any reasons for not doing so when working with Extensions.Conventions?


Solution

  • first: Please post the exact ActivationException message + Stacktrace. Most likely the binding for IService2 is missing or there is a circular dependency.

    second: Use a binding generator:

        public override void Load()
        {
            this.Bind(x => x
                .FromThisAssembly()
                .SelectAllClasses()
                .InheritedFrom<BaseClass>()
                .BindWith<ToSelfProxyBindingGenerator>()
                .Configure(binding => binding.InSingletonScope()));
        }
    
        public class ToSelfProxyBindingGenerator : IBindingGenerator
        {
            public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
            {
                yield return bindingRoot
                    .Bind(type)
                    .ToMethod(ctx => fac.CreateProxy(type));
            }
        }
    

    Also note that the singleton scope can be defined by the IBindingGenerator or @ convention using the .Configure(..) method.

    General Questions:

    1. You are correct, but i can't tell you the exact reasoning behind it.
    2. No it is perfectly fine to put conventions into different modules. We are doing this too and it works out perfectly.