2

Is there a way to have Ninject call a function when it has trouble with multiple binding resolution ?

Basically, I would like to have this:

static void Main(string[] args)
{
    StandardKernel k = new StandardKernel();
    k.Bind<IProvideConn>().To<probe1>(); // these bindings are actually done by assembly scanner, I don't know how many types are available
    k.Bind<IProvideConn>().To<probe2>();
    k.Bind<plugin1>().ToSelf();

    k.Get<plugin1>(); // Currently throws a "multiple bindings registered" exception
                      //but I would like it to call solveMyIssues.sortThingsOut
}

public class solveMyIssues
{
    public IBinding sortThingsOut(IEnumerable<IBinding> availableBindingsForThisResolve)
    {
        int i = AskChoiceFromUser(availableBindingsForThisResolve);
        return availableBindingsForThisResolve[i];
    }
}

interface IProvideConn0
{
    void goCrazy();
}

public class plugin1
{
    public void talkWithUser(IProvideConn0 pc)
    {
        pc.goCrazy();
    }
}

public class probe1 : IProvideConn0
{
    public void goCrazy() {}
}

public class probe2 : IProvideConn0
{
    public void goCrazy() {}
}

More context:
I'm using Ninject in a plugin like architecture. Plugins can use one or more types of connection providers (each connection provider type has an interface that inherits from IMotherConnProv).
Currently I use the XML extension to map each IProvideConnX to an implementation (each IProvideConnX can have several implementations), but it's quite tedious for users to edit XML files when they want to change connection types.

I made a small application that helps them modify the XML file with shiny buttons and everything, but I feel like there should be a more dynamic way to do that (Ninject is about freeing myself from XML, right ?).
So I would like to use the assembly scanner to discover all possible choices, and somehow tell Ninject at runtime which binding to choose from (depending on user choice).

Any ideas ? (I had a look at that solution but I can't see how to adapt it to an indefinite number of interfaces and implementations)

Community
  • 1
  • 1
Thibaut
  • 21
  • 1

1 Answers1

2

No you can't. But you can configure your bindings so that it won't happen:

kernel.Bind(
    x => x.FromThisAssembly()
          .SelectAllClasses().InheritedFrom<IProvideConn0>()
          .BindToAllInterfaces()
          .Configure((binding, componentType) => b.When(r => kernel.Get<IConfiguration>().ConnectionType == componentType.Name)));
kernel.Bind(
    x => x.FromThisAssembly()
          .SelectAllClasses().InheritedFrom<IConnectionType>()
          .BindToAllInterfaces();

public class Configuration : IConfiguration
{
    public Configuration(IEnumerable<IConnectionType> connectionTypes) { ... }

    public string ConnectionType
    {
        get 
        {
            return this.UserWhichConnectionDoYouWant(connectionTypes);
        }
    }
}

and add a IConnectionType for each connection specifying the nessary information to let the user select it.

See https://github.com/ninject/ninject.extensions.conventions/wiki/What-is-configuration-by-conventions

Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • That looks very good ! But I don't see how to use it, kernel.Bind doesn't seem to accept a delegate (I'm using ninject 2.2 and the conventions extension). I had a look at the unit tests in the conventions extension but couldn't find that syntax anywhere, do you have other examples ? – Thibaut Mar 13 '12 at 10:10
  • Basically, this doesn't build: using Ninject; using Ninject.Planning.Bindings; using Ninject.Extensions.Conventions; using System.Reflection; class Program { static void Main(string[] args) { using (IKernel kernel = new StandardKernel()) { kernel.Bind( x => x.From(Assembly.GetExecutingAssembly()) .SelectAllTypes() .BindToDefaultInterface() .Configure((binding, componentType) => b.When(r => true))); } } – Thibaut Mar 13 '12 at 10:16
  • This requires 3.0 form NuGet (Install-Package Ninject.Extensions.Conventions -pre) – Remo Gloor Mar 13 '12 at 11:23